diff --git a/.gitignore b/.gitignore
index 71c9194e8bd..b3235edc0fc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,10 @@ src/main/resources/docs/
/out/
/*.iml
+# VSCode files
+/bin/
+/.vscode/
+
# Storage/log files
/data/
/config.json
@@ -20,3 +24,6 @@ src/test/data/sandbox/
# MacOS custom attributes files created by Finder
.DS_Store
docs/_site/
+
+# Ruby config files for local Jekyll server
+docs/.ruby-version
diff --git a/README.md b/README.md
index 13f5c77403f..d253dc82443 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,23 @@
-[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions)
+[![Java CI](https://github.com/AY2223S1-CS2103T-T10-3/tp/actions/workflows/gradle.yml/badge.svg)](https://github.com/AY2223S1-CS2103T-T10-3/tp/actions/workflows/gradle.yml)
+[![codecov](https://codecov.io/gh/AY2223S1-CS2103T-T10-3/tp/branch/master/graph/badge.svg?token=K13DUI69HX)](https://codecov.io/gh/AY2223S1-CS2103T-T10-3/tp)
+
+# WorkBook (WB)
![Ui](docs/images/Ui.png)
-* This is **a sample project for Software Engineering (SE) students**.
- Example usages:
- * as a starting point of a course project (as opposed to writing everything from scratch)
- * as a case study
-* The project simulates an ongoing software project for a desktop application (called _AddressBook_) used for managing contact details.
- * It is **written in OOP fashion**. It provides a **reasonably well-written** code base **bigger** (around 6 KLoC) than what students usually write in beginner-level SE modules, without being overwhelmingly big.
- * It comes with a **reasonable level of user and developer documentation**.
-* It is named `AddressBook Level 3` (`AB3` for short) because it was initially created as a part of a series of `AddressBook` projects (`Level 1`, `Level 2`, `Level 3` ...).
-* For the detailed documentation of this project, see the **[Address Book Product Website](https://se-education.org/addressbook-level3)**.
-* This project is a **part of the se-education.org** initiative. If you would like to contribute code to this project, see [se-education.org](https://se-education.org#https://se-education.org/#contributing) for more info.
+* WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications.
+
+* WorkBook (WB) is optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, WB can get your internship management tasks done faster than traditional GUI apps.
+
+## Usage
+
+* Manage your internship applications for easier tracking!
+
+
+## Acknowledgements
+Libraries used: [JavaFX](https://openjfx.io), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5).
+This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
+User Guide: Table of Contents with bullet points removed is reused from [@ianyong's team in 2020](https://github.com/AY2021S1-CS2103T-W16-3/tp/pull/190/commits/b91ca546a6a41a977a8dbf4d40c969ab07a49ad7).
+Reused [code](https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110) from CS2103T-T10-4 to parse optional arguments.
+
+
diff --git a/build.gradle b/build.gradle
index 108397716bd..348420ace46 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,7 +6,7 @@ plugins {
id 'jacoco'
}
-mainClassName = 'seedu.address.Main'
+mainClassName = 'seedu.workbook.Main'
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
@@ -16,6 +16,10 @@ repositories {
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
+run {
+ enableAssertions = true
+}
+
checkstyle {
toolVersion = '10.2'
}
@@ -66,7 +70,7 @@ dependencies {
}
shadowJar {
- archiveFileName = 'addressbook.jar'
+ archiveFileName = 'workbook.jar'
}
defaultTasks 'clean', 'test'
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index d618671b832..261d8e91a42 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -10,6 +10,13 @@
+
+
+
+
+
+
+
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..a9caf452c05 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -9,51 +9,51 @@ You can reach us at the email `seer[at]comp.nus.edu.sg`
## Project team
-### John Doe
+### Daryl Chua
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/rylzxc)]
+[[portfolio](team/rylzxc.md)]
-* Role: Project Advisor
+* Role: Team Lead
+* Responsibilities: Overall project coordination, deliverables and deadlines
-### Jane Doe
+### Adee Aryaa
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/adeearyaa)]
+[[portfolio](team/adeearyaa.md)]
-* Role: Team Lead
-* Responsibilities: UI
+* Role: Code Quality
+* Responsibilities: Ensures that Code follows a common style and achieves maximum readability
-### Johnny Doe
+### Glemen Neo
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/glemenneo)] [[portfolio](team/glemenneo.md)]
-* Role: Developer
-* Responsibilities: Data
+* Role: UI/UX
+* Responsibilities: Designing and implementing UI elements for new features, improving user experience by redesigning existing UI elements.
-### Jean Doe
+### Jacob Kwan
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/jacobkwan)]
+[[portfolio](team/jacobkwan.md)]
-* Role: Developer
-* Responsibilities: Dev Ops + Threading
+* Role: Integration
+* Responsibilities: Versioning of codebase/releases and overall maintenance of the repository.
-### James Doe
+### Tien Yu
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/tienyu2000)]
+[[portfolio](team/tienyu2000.md)]
-* Role: Developer
-* Responsibilities: UI
+* Role: Documentation
+* Responsibilities: JavaDocs to generate API documentation in HTML format
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 46eae8ee565..4277f9196e2 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -9,7 +9,11 @@ title: Developer Guide
## **Acknowledgements**
-* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+* Libraries used: [JavaFX](https://openjfx.io), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5).
+* This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
+* User Guide: Table of Contents with bullet points removed is reused from [@ianyong's team in 2020](https://github.com/AY2021S1-CS2103T-W16-3/tp/pull/190/commits/b91ca546a6a41a977a8dbf4d40c969ab07a49ad7).
+* Reused [code](https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110) from CS2103T-T10-4 to parse optional arguments.
+* Reused [code](https://github.com/se-edu/addressbook-level4/blob/master/src/main/java/seedu/address/model/VersionedAddressBook.java) from AddressBook-Level4.
--------------------------------------------------------------------------------------------------------------------
@@ -73,7 +77,7 @@ The **API** of this component is specified in [`Ui.java`](https://github.com/se-
![Structure of the UI Component](images/UiClassDiagram.png)
-The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
+The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `InternshipListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml)
@@ -82,7 +86,7 @@ The `UI` component,
* executes user commands using the `Logic` component.
* listens for changes to `Model` data so that the UI can be updated with the modified data.
* keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands.
-* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`.
+* depends on some classes in the `Model` component, as it displays `Internship` object residing in the `Model`.
### Logic component
@@ -93,9 +97,9 @@ Here's a (partial) class diagram of the `Logic` component:
How the `Logic` component works:
-1. When `Logic` is called upon to execute a command, it uses the `AddressBookParser` class to parse the user command.
+1. When `Logic` is called upon to execute a command, it uses the `WorkBookParser` class to parse the user command.
1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `AddCommand`) which is executed by the `LogicManager`.
-1. The command can communicate with the `Model` when it is executed (e.g. to add a person).
+1. The command can communicate with the `Model` when it is executed (e.g. to add an internship).
1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
The Sequence Diagram below illustrates the interactions within the `Logic` component for the `execute("delete 1")` API call.
@@ -110,7 +114,7 @@ Here are the other classes in `Logic` (omitted from the class diagram above) tha
How the parsing works:
-* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object.
+* When called upon to parse a user command, the `WorkBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `WorkBookParser` returns back as a `Command` object.
* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing.
### Model component
@@ -121,12 +125,12 @@ How the parsing works:
The `Model` component,
-* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object).
-* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
+* stores the work book data i.e., all `Internship` objects (which are contained in a `UniqueInternshipList` object).
+* stores the currently 'selected' `Internship` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects.
* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components)
-
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
+
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `WorkBook`, which `Internship` references. This allows `WorkBook` to only require one `Tag` object per unique tag, instead of each `Internship` needing their own `Tag` objects.
@@ -140,13 +144,13 @@ The `Model` component,
The `Storage` component,
-* can save both address book data and user preference data in json format, and read them back into corresponding objects.
-* inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
+* can save both work book data and user preference data in json format, and read them back into corresponding objects.
+* inherits from both `WorkBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`)
### Common classes
-Classes used by multiple components are in the `seedu.addressbook.commons` package.
+Classes used by multiple components are in the `seedu.workbook.commons` package.
--------------------------------------------------------------------------------------------------------------------
@@ -154,41 +158,110 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa
This section describes some noteworthy details on how certain features are implemented.
-### \[Proposed\] Undo/redo feature
+### Add feature
-#### Proposed Implementation
+#### 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:
+The add feature is facilitated by `AddCommand` and `AddCommandParser` classes. The `parse` method in `AddCommandParser`
+checks if mandatory fields are first present.
+If all are present, the new `Internship` will be added to the `UniqueInternshipList` in a sorted-by-date order.
-* `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.
+Below shows the class diagram of adding a new internship application into the list which automatically sorts using `SortedList`.
+This takes place in the `UniqueInternshipList` as shown in the diagram below.
+Some `logic` and `model` details are omitted as they are already explained in the [Architecture section](#architecture) above.
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
+
+
+#### Design considerations:
+
+**Aspect: `Stage` field:**
+
+* **Alternative 1 (current choice):** Not restricting to enums, (proposed: warn if input does not match general stages)
+ * Pros: Flexibility for user by allowing unique stages from different companies which we did not prepare for to be added.
+ * Cons: Will not have stage-specific tips that have been gathered for more general interview stages.
+
+* **Alternative 2:** Restricting to enums
+ * Pros: Prevent the need for user to edit previous command in the event of a typo,
+ * Cons: Flexibility is heavily restricted, user may encounter stages that we may not have prepared for, which may annoy the user if the user is not allowed to add the stage into the internship tracker.
+
+**Aspect: `DateTime` field:**
+
+* **Alternative 1 (current choice):** Not modularizing Time and Date
+ * Pros: Most stages have a date and time associated with it. Making one of the two optional takes extra effort for something that uncommon. Can be left to later stages of development.
+ * Cons: May not be prepared for stages without date and/or time, therefore not making the tracker flexible enough.
+
+* **Alternative 2:** Modularizing Time and Date
+ * Pros: Some stages that we may not have prepared for may omit date or time, encouraging flexibility of the tracker.
+ * Cons: Effort required is too high in the early stages of development whereby a functional product is prioritized.
+
+
+### Find feature
+
+#### Implementation
+
+The find feature is facilitated by `FindCommand` and `FindCommandParser` classes. The `parse` method in `FindCommandParser`
+checks if mandatory fields are first present.
+If all are present, the new `UniqueInternshipList` will contain the internships that contain the keywords the user's have entered.
+
+Below shows the class diagram of filtering existing internship applications using keywords that are input by the user. The list will only contain internships that pass the predicate. This list automatically sorts using `SortedList`.
+This takes place in the `UniqueInternshipList` as shown in the diagram below.
+Some `logic` and `model` details are omitted as they are already explained in the [Architecture section](#architecture) above.
+
+
+
+#### Design considerations:
+
+**Aspect: Not allowing user's to find internships using more than one attribute:**
+
+* **Alternative 1 (current choice):** Only allowing keywords from one attribute, (an error message displayed if user inputs keywords corresponding to more than one attribute)
+ * Pros: Allows user to be able to filter internship applications by one attribute of their interest(e.g. Company, Role or Stage).
+ If user was allowed to filter by more than one attribute it will result in them being able to see internships that did not match the other attributes they have input.
+
+ * Cons: User will not be able to filter their internship application listings by more than attribute.
+
+* **Alternative 2:** Allowing user to filter internships by more than one attribute
+ * Pros: Allows user to filter and find internships using keywords belonging to multiple attributes.
+ * Cons: Will result in the user being able to see internships that did not contain keywords of one of the attributes but contained another keyword of another attribute. This is possibly unwanted behaviour.
+
+
+### Undo/Redo feature
+
+The undo feature allows for users to revert back to their previous undone state in the Workbook.
+The redo feature complements the undo feature by allowing users to restore to its previous changed state following an undo command.
+
+#### Implementation
+
+The undo/redo mechanism is facilitated by `VersionedWorkBook`. It extends `WorkBook` with an undo/redo history, stored internally as an `workBookStateList` and `currentStatePointer`. Additionally, it implements the following operations:
+
+* `VersionedWorkBook#commit()` — Saves the current work book state in its history.
+* `VersionedWorkBook#undo()` — Restores the previous work book state from its history.
+* `VersionedWorkBook#redo()` — Restores a previously undone work book state from its history.
+
+These operations are exposed in the `Model` interface as `Model#commitWorkBook()`, `Model#undoWorkBook()` and `Model#redoWorkBook()` 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.
+Step 1. The user launches the application for the first time. The `VersionedWorkBook` will be initialized with the initial work book state, and the `currentStatePointer` pointing to that single work 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.
+Step 2. The user executes `delete 5` command to delete the 5th internship in the work book. The `delete` command calls `Model#commitWorkBook()`, causing the modified state of the work book after the `delete 5` command executes to be saved in the `workBookStateList`, and the `currentStatePointer` is shifted to the newly inserted work 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`.
+Step 3. The user executes `add c/COMPANY …` to add a new internship. The `add` command also calls `Model#commitWorkBook()`, causing another modified work book state to be saved into the `workBookStateList`.
![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`.
+
:information_source: **Note:** If a command fails its execution, it will not call `Model#commitWorkBook()`, so the work book state will not be saved into the `workBookStateList`.
-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.
+Step 4. The user now decides that adding the internship was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoWorkBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous work book state, and restores the work 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
+
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial WorkBook state, then there are no previous WorkBook states to restore. The `undo` command uses `Model#canUndoWorkBook()` to check if this is the case. If so, it will return an error to the user rather
than attempting to perform the undo.
@@ -201,20 +274,30 @@ The following sequence diagram shows how the undo operation works:
-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.
+Step 5. The user now decides that undoing the added internship was a mistake, and decides to redo that action by executing the `redo` command. The `redo` command will call `Model#redoWorkBook()`, which will shift the `currentStatePointer` once to the right, pointing it to the previous undone work book state, and restores the work book to that state.
+
+![UndoRedoState4](images/UndoRedoState4.png)
-
: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.
+
:information_source: **Note:** If the `currentStatePointer` is at index `workBookStateList.size() - 1`, pointing to the latest work book state, then there are no undone WorkBook states to restore. The `redo` command uses `Model#canRedoWorkBook()` 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.
+The following sequence diagram shows how the redo operation works:
-![UndoRedoState4](images/UndoRedoState4.png)
+![RedoSequenceDiagram](images/RedoSequenceDiagram.png)
+
+
:information_source: **Note:** The lifeline for `RedoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
-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.
+
+
+Step 6. The user then decides to execute the command `list`. Commands that do not modify the work book, such as `list`, will usually not call `Model#commitWorkBook()`, `Model#undoWorkBook()` or `Model#redoWorkBook()`. Thus, the `workBookStateList` remains unchanged.
![UndoRedoState5](images/UndoRedoState5.png)
+Step 7. The user executes `clear`, which calls `Model#commitWorkBook()`. Since the `currentStatePointer` is not pointing at the end of the `workBookStateList`, all work book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add c/COMPANY …` command. This is the behavior that most modern desktop applications follow.
+
+![UndoRedoState6](images/UndoRedoState6.png)
+
The following activity diagram summarizes what happens when a user executes a new command:
@@ -223,15 +306,82 @@ The following activity diagram summarizes what happens when a user executes a ne
**Aspect: How undo & redo executes:**
-* **Alternative 1 (current choice):** Saves the entire address book.
+* **Alternative 1 (current choice):** Saves the entire work 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).
+ * Pros: Will use less memory (e.g. for `delete`, just save the internship being deleted).
* Cons: We must ensure that the implementation of each individual command are correct.
+### Help window feature
+
+The help window has been redesigned to show all the commands supported by WB as well as examples of how to use the commands. This is to enable ease of use as users can quickly reference commands from the help window instead of having to open and refer to the UG.
+
+#### Implementation
+
+The help window is implemented in the `HelpWindow` class. The `HelpUtil` class stores all the headers and examples `String`s for the commands in a two `HashMap`s. The help window will retrieve the list of `Command`s and then builds a `HelpCard` for each command and adds it into the `GridPane` to display in the `HelpWindow`. The `HelpCard` retrieves the respective header and example `String`s using the `getCommandHeader` and `getCommandExample` methods from `HelpUtil` and shows it using two `Label`s.
+
+### Tips feature
+
+The tips feature shows curated tips for internship applications for specific application stages in order to help the user prepare for their certain deliverables, interviews and tests. The tips are currently only curated for common stages of internship applications due to the feasibility constraints.
+
+#### Implementation
+
+The tips feature is implemented in the `Model` component inside the `StageUtil` class. The list of supported stages is stored inside as a `List`. The tips are stored in a `HashMap` that maps each `Stage` object to their respective `List` of tips. The `getStageSpecificTips()` method will retrieve the list of tips for a supported stage as a `List`.
+
+The tips are then stored and shown inside a `TipsCard` object that extends from `UiPart` and consists of one `Hbox` housing 2 `Hbox`s with each inner `Hbox` containing a `Label`. The first `Label` shows the index while the second `Label` shows the Tip itself.
+
+The tips are show to the user in one of two ways depending on the UI layout.
+
+##### Narrow UI implementation
+In the narrow UI layout, the tips can be accessed through a `tipsButton` which has a light bulb icon on the `NarrowInternshipCard` which will open the `TipsWindow`. The `TipsWindow` is a member of every `NarrowInternshipCard` object and is created when the constructor is called.
+
+The light bulb button will only appear if the internship application is at a supported stage, The implementation of this is through the `hasNoTips()` method from the `Stage` class that returns a boolean `hasNoTips` depending on whether the stage of the application has tips.
+
+If the application stage has tips and the button is pressed, the `TipsWindow` UI component of the `InternshipCard` will have its `GridPane` populated with `TipsCard` vertically after retrieving the tips using the `getStageSpecificTips()` method and building the `TipsCard` for each tip. The tips window is then opened.
+
+If the application stage does not have tips, the tips button will be set to hidden and the `TipsWindow` will not be populated and will be inaccessible.
+
+For more details on the UI implementation, please refer to the [Responsive UI](#responsive-ui-feature) section of the DG.
+
+##### Wide UI implementation
+In the wide UI layout, the tips are shown to the right of the internship list using the `TipsPanel` that extends `UiPart`. A listener is implemented in the `WideInternshipListPanel` to check which `NarrowInternshipCard` is currently selected.
+
+
+If the internship card currently selected is at a supported stage, the `TipsPanel` will have its `GridPane` populated with `TipCard`s vertically after retrieving the tips using the `getStageSpecificStips()` method and building the `TipCard` for each tip.
+
+If the internship card currently selected is not at a supported stage, the default `TipsPanel` will be shown which only has `Label` message telling the user that there are no tips for the stage yet.
+
+For more detail on the UI implementation, please refer to the [Responsive UI](#responsive-ui-feature) section of the DG.
+
+### Responsive UI feature
+
+Workbook had two UI layouts depending on the size of the `MainWindow`. A narrow UI layout is shown when the window is resized narrower than the 1000 pixel breakpoint and a wide UI layout is shown when the window is resized wider than the 1000 pixel breakpoint. This is to improve readability and usability on narrow and wide screens.
+
+#### Implementation
+
+The implementation starts at the `MainWindow` class. The class has two UI layouts as members, the `WideInternshipListPanel` class and the `NarrowInternshipListPanel` class that both extend `UiPart`. The two UI layout objects are instantiated on calling the constructer of `MainWindow` and are populated with the internship applications on instantiation. This is to enable fast switching between the two layouts.
+
+The `setWidthEventHandlers()` listener will listen to the current window width. Whenever the window width passes the breakpoint, the `internshipListPanelPlaceholder` is cleared and populated with either the `WideInternshipListPanel` or the `NarrowInternshipListPanel` depending on the window width.
+
+##### Narrow UI
+
+The narrow UI layout uses the `NarrowInternshipListPanel` and populates its `ListView` with the `InternshipCard` that extends `UiPart`. It has a tips button that can open the tips window. Other than the tips button, the implementation is very similar to AB3 with minor styling changes.
+
+For more details on the implementation of the tips button and tips window, refer to the [Tips section](#tips-feature) of the DG.
+
+##### Wide UI
+The wide UI layout uses the `WideInternshipListPanel` and populates its `ListView` with the `NarrowInternshipCard` that extends `UiPart`. It differs from the `InternshipCard` in that it does not have the tips button. The implementation is very similar to the original `InternshipCard` from AB3 with minor styling changes.
+
+The `WideInternshipListPanel` has a `TipsPanel` beside the `ListView` that extends `UiPart`. The `TipsPanel` is contained inside a `HBox` `tipsPanelContainer` which is a member of the `WideInternshipListPanel`.
+
+A listener `setInternshipSelectedEventHandlers()` is implemented in the `WideInternshipListPanel` class that listens to to which `NarrowInternshipCard` is currently selected. It will call the `tipPanelBuilder()` method which takes in a `Stage` and creates a `TipsPanel` object and populates it with tips.
+
+For more details on the implementation of the tips button, tips window and tips panel, refer to the [Tips section](#tips-feature) of the DG.
+
+
_{more aspects and alternatives to be added}_
### \[Proposed\] Data archiving
@@ -257,71 +407,223 @@ _{Explain here how the data archiving feature will be implemented}_
**Target user profile**:
-* has a need to manage a significant number of contacts
+* is a Computing student
+* is looking and applying for internships
+* likes to organize his/her data in one place
* prefer desktop apps over other types
* can type fast
* prefers typing to mouse interactions
* is reasonably comfortable using CLI apps
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+**Value proposition**: This app aims to be a unified platform that helps the user manage all their internship applications
### User stories
Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-| Priority | As a … | I want to … | So that I can… |
-| -------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------- |
-| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App |
-| `* * *` | user | add a new person | |
-| `* * *` | user | delete a person | remove entries that I no longer need |
-| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list |
-| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident |
-| `*` | user with many persons in the address book | sort persons by name | locate a person easily |
+| Priority | As a … | I want to … | So that I can… |
+|----------|-----------------------------------------------|-----------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|
+| `* * *` | student | add an internship company and role that I have applied to | keep track of which company and which roles I have applied for, especially when I have many applications |
+| `* * *` | student | update an internship position that I have applied to | keep the tracker updated on the current state of my internship application |
+| `* * *` | student | add an interview date and time to an internship application | track when my interview for that particular internship application is coming up |
+| `* * *` | student | view the list of commands for use | familiarize myself with them and increase efficiency when performing operations on the application |
+| `* * *` | student | keep track of the stage of my application | know which stages I am at for each application and thereafter what to prepare for it |
+| `* * *` | student | delete an internship that I am not interested in anymore | get rid of internship applications that are not relevant to me anymore |
+| `* * *` | forgetful student | sort the list of internship applications by dates | see and remember which interviews are upcoming to better prepare for them in case I have forgotten about them |
+| `* * *` | student who got rejected by all the companies | clear the list of internship applications | I can start anew |
+| `* * *` | student | add an expiry date and time to an application that is in the “Online Assessment” stage | keep track of when I have to complete the Online Assessment by |
+| `* * *` | student who constantly changes my mind | redo an undone command | revert back the changes I had originally made |
+| `* *` | easily confused student | prevent myself from adding the same internship application twice | I don't get distracted by duplicate internships |
+| `* *` | forgetful student | easily access tips specific to each application based on the current stage | quickly see a list of things to prepare for an upcoming interview or deadline |
+| `* *` | student | filter my internship applications according to position | view all my internship applications for that particular position that I am interested in |
+| `* *` | student preparing for technical interviews | conveniently do practice questions | be better prepared for my technical interviews |
+| `* *` | broke student | sort the internships based on pay | determine which applications are more worth it in this current economic state |
+| `*` | student | rank all my internship applications | decide which applications that I have to focus on more |
+| `*` | student | move an existing application to the "Rejection" stage and provide a reason why I got rejected | keep track of common trends or reasons for my failed applications |
+| `*` | less experienced student | view some helpful resources | understand the hiring process and tech landscapes better |
+| `*` | anxious student | switch to a calender view | easily see all my upcoming interviews/OAs/expiring offers |
+| `*` | student | create a todo list for each internship entry | keep track of what I've done and what I've yet to do to prepare |
-*{More to be added}*
### 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 `WorkBook` and the **Actor** is the `user`, unless specified otherwise)
+
+**Use case: UC01 - Add an internship application**
+
+**Main Success Scenario (MSS)**
+
+1. User requests to add an internship.
+2. WorkBook adds the internship.
+3. WorkBook displays internship addition is successful.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. The internship already exists.
+
+ * 1a1. WorkBook shows an error message.
+
+ Use case ends.
+
+* 1b. The format of given command is invalid.
+ * 1b1. WorkBook shows an error message.
+
+ Use case ends.
+
+
+**Use case: UC02 - Delete an internship application**
+
+**Main Success Scenario (MSS)**
-**Use case: Delete a person**
+1. User requests to delete an internship.
+2. WorkBook deletes the internship.
+3. WorkBook displays list of internships remaining when successful.
-**MSS**
+ Use case ends.
+
+**Extensions**
-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
+* 1a. The list is empty.
Use case ends.
+* 1b. The given index is invalid.
+
+ * 1b1. WorkBook shows an error message.
+
+ Use case ends.
+
+
+**Use case: UC03 - Edit an internship application**
+
+**Main Success Scenario (MSS)**
+
+1. User requests to edit an internship.
+2. WorkBook edits the internship.
+3. WorkBook displays list of internships when successful.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. The list is empty.
+
+ * 1a1. WorkBook shows an error message.
+
+ Use case ends.
+
+* 1b. The given field is invalid.
+
+ * 1b1. WorkBook shows an error message.
+
+ Use case ends.
+
+* 1c. The edited internship is identical to one in the list.
+
+ * 1c1. WorkBook shows an error message.
+
+ Use case ends.
+
+
+**Use case: UC04 - Undo a command**
+
+**Main Success Scenario (MSS)**
+
+1. User requests to undo the latest command they have executed.
+2. Workbook reverts any changes made by the command and displays the previous state of the list of internship applications.
+
+ Use case ends.
+
**Extensions**
-* 2a. The list is empty.
+* 1a. There is no previous command executed and the list is empty.
- Use case ends.
+ * 1a1. WorkBook displays an error message that no previous command has been entered.
-* 3a. The given index is invalid.
+ Use case ends.
+
+
+**Use case: UC05 - Redo a command**
- * 3a1. AddressBook shows an error message.
+**Main Success Scenario (MSS)**
- Use case resumes at step 2.
+1. User requests to redo the latest command they have undone.
+2. Workbook reverts any changes made by the undo command and displays the previous state of the list of internship applications.
-*{More to be added}*
+ Use case ends.
+
+**Extensions**
+
+* 1a. There is no previous command executed and the list is empty.
+
+ * 1a1. WorkBook displays an error message that no commands can be redone.
+
+ Use case ends.
+
+
+**Use case: UC06 - Clear list of internship applications**
+
+**Main Success Scenario (MSS)**
+
+1. User requests to clear list.
+2. List is cleared.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. The list is empty.
+
+ * 1a1. WorkBook shows an error message.
+
+ Use case ends.
+
+
+**Use case: UC07 - Display help message**
+
+**Main Success Scenario (MSS)**
+
+1. User requests for help.
+2. Help message is shown.
+
+ Use case ends.
+
+
+**Use case: UC08 - Exit application**
+
+**Main Success Scenario (MSS)**
+
+1. User requests to exit program.
+2. WorkBook exits and closes.
+
+ Use case ends.
+
+
+**Use case: UC09 - View preparatory tips based on internship stage**
+
+1. User requests to view preparatory tips.
+2. User chooses internship stage to view preparatory tips for.
+3. The preparatory tips for the internship stage is shown to the user.
+
+ Use case ends.
### Non-Functional Requirements
1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
-2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
-3. 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.
-
-*{More to be added}*
+2. Should have a startup time of at most 1 second.
+3. Should be able to hold up to 200 internship applications without any noticeable sluggishness in performance for typical usage.
+4. 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.
+5. Data should be persisted locally and be in a human-readable format, for e.g `json`.
+6. User interface and documentation should be intuitive enough so that new users can add an internship application within 15 minutes of installation.
### Glossary
* **Mainstream OS**: Windows, Linux, Unix, OS-X
-* **Private contact detail**: A contact detail that is not meant to be shared with others
+* **OA/Online Assessment**: A common stage in a Software Engineering related internship application, where applicants are required to solve several theory and/or algorithmic questions under a timed and controlled environment
+
--------------------------------------------------------------------------------------------------------------------
@@ -340,7 +642,7 @@ testers are expected to do more *exploratory* testing.
1. Download the jar file and copy into an empty folder
- 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
+ 1. Double-click the jar file Expected: Shows the GUI with a set of sample internship applications. The window size may not be optimum.
1. Saving window preferences
@@ -349,29 +651,40 @@ testers are expected to do more *exploratory* testing.
1. Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-1. _{ more test cases … }_
+### Deleting an internship application
-### Deleting a person
-
-1. Deleting a person while all persons are being shown
+1. Deleting an internship application while all applications are being shown
1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated.
+ Expected: First application is deleted from the list. Details of the deleted application shown in the status message.
1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
+ Expected: No application is deleted. Error details shown in the status message.
- 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
+ 1. Other incorrect delete commands to try: `delete`, `delete x` (where x is larger than the list size)
Expected: Similar to previous.
-1. _{ more test cases … }_
-
### Saving data
-1. Dealing with missing/corrupted data files
+1. Dealing with missing data file.
+
+ 1. Simulate a missing data file by deleting `data/workbook.json` (if it exists).
+
+ 1. Start `WorkBook` and it should be populated with sample data.
+
+ 1. Execute `exit` command.
+
+ 1. `data/workbook.json` should be saved with the sample data.
+
+1. Dealing with corrupted data file.
+
+ 1. Simulate a corrupted data file by manually editing `data/workbook.json`. Delete the `company` field from one of the internship applications.
+
+ 1. Start `WorkBook` and it should have no data at all.
+
+ 1. Execute `exit` command.
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
+ 1. `data/workbook.json` should only contain: `{ "internships" : [] }`.
-1. _{ more test cases … }_
diff --git a/docs/SettingUp.md b/docs/SettingUp.md
index 275445bd551..96218530f67 100644
--- a/docs/SettingUp.md
+++ b/docs/SettingUp.md
@@ -23,7 +23,7 @@ If you plan to use Intellij IDEA (highly recommended):
1. **Import the project as a Gradle project**: Follow the guide [_[se-edu/guides] IDEA: Importing a Gradle project_](https://se-education.org/guides/tutorials/intellijImportGradleProject.html) to import the project into IDEA.
:exclamation: Note: Importing a Gradle project is slightly different from importing a normal Java project.
1. **Verify the setup**:
- 1. Run the `seedu.address.Main` and try a few commands.
+ 1. Run the `seedu.workbook.Main` and try a few commands.
1. [Run the tests](Testing.md) to ensure they all pass.
--------------------------------------------------------------------------------------------------------------------
diff --git a/docs/Testing.md b/docs/Testing.md
index 8a99e82438a..a40481a3e69 100644
--- a/docs/Testing.md
+++ b/docs/Testing.md
@@ -29,8 +29,8 @@ There are two ways to run tests.
This project has three types of tests:
1. *Unit tests* targeting the lowest level methods/classes.
- e.g. `seedu.address.commons.StringUtilTest`
+ e.g. `seedu.workbook.commons.StringUtilTest`
1. *Integration tests* that are checking the integration of multiple code units (those code units are assumed to be working).
- e.g. `seedu.address.storage.StorageManagerTest`
+ e.g. `seedu.workbook.storage.StorageManagerTest`
1. Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
- e.g. `seedu.address.logic.LogicManagerTest`
+ e.g. `seedu.workbook.logic.LogicManagerTest`
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 3716f3ca8a4..cf24216f043 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -3,190 +3,546 @@ layout: page
title: User Guide
---
-AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB3 can get your contact management tasks done faster than traditional GUI apps.
+
+ * Table of Contents
+ {:toc}
+
+
+--------------------------------------------------------------------------------------------------------------------
+
+
+
+## 1. Introducing WorkBook
+
+Welcome to WorkBook! :wave:
+
+WorkBook is an **internship application tracker** that helps Computing students **prepare sufficiently** for their upcoming interviews to secure that internship.
+This minimalistic tool allows you to effortlessly collate and easily manage all of your internship applications' progress.
+Furthermore, **tips are given for relevant stages** of your internship applications to give you an edge over other applicants!
+
+This guide provides a step-by-step guide on how you can get started using WorkBook, gives an overview of what you can do in WorkBook and how you can best utilise it to transform your internship hunt positively.
+Each documented feature introduces a potential problem you face, how it can be resolved and examples on using the feature.
-* Table of Contents
-{:toc}
+No time to waste, let's start _Working_! :muscle:
--------------------------------------------------------------------------------------------------------------------
-## Quick start
+## 2. Getting started
+
+This section helps you get started with WorkBook.
+
+It consists of a step-by-step installation guide and an explanation of the key GUI elements.
+
+### 2.1 Installation
+
+1. Ensure you have [Java 11 or above](https://www.oracle.com/sg/java/technologies/downloads/#java11) installed on your computer.
+
+2. Download the latest `WorkBook.jar` from [here](https://github.com/AY2223S1-CS2103T-T10-3/tp/releases/).
+
+3. Copy the downloaded `WorkBook.jar` to a folder of your choice.
+
+4. Using your command terminal:
+ 1. Navigate to the folder where you placed your WorkBook at.
+ 2. Run: `java -jar WorkBook.jar`. The GUI, as shown below in one of the two layouts, should appear within seconds.
+
+
-1. Ensure you have Java `11` or above installed in your Computer.
+| Wide Layout | Narrow Layout |
+|:------------------------------:|:-------------------------------------:|
+| ![wide layout](images/Ui2.png) | ![narrow layout](images/UiNarrow.png) |
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+5. Tell WorkBook what you want to do by typing your command in `Enter command here...` at the top of the application and pressing Enter on your keyboard to execute it.
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+6. Before diving right into using WorkBook, familiarise yourself with the [things to note](#4-things-to-note) to not hinder your tracking process!
-1. Double-click the file to start the app. The GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- ![Ui](images/Ui.png)
+
-1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.
- Some example commands you can try:
+### 2.1 Understanding WorkBook's GUI
- * **`list`** : Lists all contacts.
+Below shows the main elements of WorkBook's GUI, in wide and narrow layouts.
- * **`add`**`n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : Adds a contact named `John Doe` to the Address Book.
+For the narrow layout, everything else is the same except for the labelled light bulb icon, which displays tips.
- * **`delete`**`3` : Deletes the 3rd contact shown in the current list.
+| Wide Layout |
+|:--------------------------------------:|
+| ![wide layout](images/AnnotatedUi.png) |
- * **`clear`** : Deletes all contacts.
+
- * **`exit`** : Exits the app.
+| Narrow Layout |
+|:------------------------------------------------------:|
+| ![narrow layout](images/AnnotatedUiNarrowBulbOnly.png) |
-1. Refer to the [Features](#features) below for details of each command.
--------------------------------------------------------------------------------------------------------------------
+## 3. Exploring our guide
-## Features
+**Information Box**
+**:information_source: Info:** Provides extra information that is useful
+
+
+**Warning Box**
+
+**:exclamation: Warning: Important messages**
+
+
+**Tip Box**
+
+**:bulb: Tip:** Provides pointers to enhance your experience using the application
+
+
+**Highlights**
+`commands` or `PARAMETERS`
+
+--------------------------------------------------------------------------------------------------------------------
-**:information_source: Notes about the command format:**
+## 4. Things to note
+
+This section describes important information for you to take note of before and while using WorkBook. In order to make WorkBook work best for you, do familiarise yourself with the items in this section.
+
+### 4.1 Notes about the command format:
* Words in `UPPER_CASE` are the parameters to be supplied by the user.
- e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`.
+ e.g. in `add c/COMPANY`, `COMPANY` is a parameter which can be used as `add c/Meta`.
* 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`.
+ e.g `c/COMPANY [t/TAG]` can be used as `c/Meta t/unattainable` or as `c/Meta`.
* Items with `…` after them can be used multiple times including zero times.
- e.g. `[t/TAG]…` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc.
+ e.g. `[t/TAG]…` can be omitted, used once: `t/unattainable`, or multiple times: `t/unattainable t/AWS`.
* 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.
+ e.g. if the command specifies `c/COMPANY s/STAGE`, `s/STAGE c/COMPANY` is also acceptable.
-* If a parameter is expected only once in the command but you specified it multiple times, only the last occurrence of the parameter will be taken.
- e.g. if you specify `p/12341234 p/56785678`, only `p/56785678` will be taken.
+* If a parameter is expected only once in the command, but you specified it multiple times, only the last occurrence of the parameter will be taken.
+ e.g. if you specify `r/Frontend r/Backend`, only `r/Backend` will be taken.
* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`.
+### 4.2 Parameter-specific behaviour
+
+* Whenever `[d/DATETIME]` is specified as a parameter, you should input it in the format `dd-MMM-yyy hh:mm` where `y` is year, `M` is month, `d` is day, `h` is hour in the 24-hour format and `m` is minutes.
+ e.g. October 2 2022 5:00pm should be inputted as `02-Oct-2022 17:00`.
+ * Month is not case-sensitive
+
+### 4.3 Behaviour of sorted internship applications
+
+* The list of applications are sorted downwards from the closest upcoming application to furthest.
+* Those with no `DATETIME` attached to it will be placed below those with upcoming dates.
+* Applications in the past (i.e. `DATETIME` is past current time) will be placed at the bottom of the list, sorted downwards as well from the most recently passed.
+* An example is shown below:
+![SortExample](images/SortExample.png)
+
+
+
+### 4.4 Responsive UI when resizing window
+
+* The UI will change dynamically depending on the window width.
+
+* If the window width is too small, WorkBook will switch to a narrow layout for a better UX.
+
+* Otherwise, WorkBook will be in the wide layout which has an extra right panel for displaying tips.
+
+| Wide Layout |
+|:--------------------------------------:|
+| Resize the window to a wider width to get this layout |
+| ![wide layout](images/AnnotatedUi.png) |
+
+
+
+| Narrow Layout |
+|:------------------------------------------------------:|
+| Resize the window to a narrower width to get this layout |
+| ![narrow layout](images/AnnotatedUiNarrowBulbOnly.png) |
+
+
+
+## 5. What you can do
+
+| Your action | Command format e.g. Example command (If applicable) |
+|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Add** | `add c/COMPANY r/ROLE s/STAGE [d/DATETIME] [e/COMPANY_EMAIL] [l/LANGUAGE TAG]… [t/TAG]…` e.g., `add c/Bytedance r/Backend Engineer s/Online Assessment d/24-Sep-2022 15:00 t/high pay l/Javascript` |
+| **Edit** | `edit INDEX [c/COMPANY] [d/DATETIME] [e/COMPANY_EMAIL] [r/ROLE] [l/LANGUAGE TAG]… [t/TAG]…` e.g.,`edit 2 c/Meta e/hr@meta.com` |
+| **Find** | `find [c/COMPANY] [r/ROLE] [s/STAGE]` e.g., `find c/Meta` |
+| **Delete** | `delete INDEX` e.g., `delete 3` |
+| **List** | `list` |
+| **Undo** | `undo` |
+| **Redo** | `redo` |
+| **Clear** | `clear` |
+| **Help** | `help` |
+| **Exit** | `exit` |
+
+
+**:information_source: Note:**
+* Commands without examples are considered trivial and can be executed by inputting the command without additional parameters.
+* Commands are **case-sensitive**!
+
-### Viewing help : `help`
+### 5.1. Adding your internship application
-Shows a message explaning how to access the help page.
+Have you taken the first step to apply for that internship you've always wanted?
+Or do you want to start keeping track of the different internship applications you have?
-![help message](images/helpMessage.png)
+This command satisfies the above, allowing you to add your internship applications to the list and track all of them.
+WorkBook also removes the hassle of sorting your internship applications manually by automating it for you!
-Format: `help`
+Simply follow the command format below to add the relevant details into WorkBook!
+Format: `add c/COMPANY r/ROLE s/STAGE [d/DATETIME] [e/COMPANY_EMAIL] [l/LANGUAGE TAG]… [t/TAG]…`
-### Adding a person: `add`
+Example: `add c/Meta r/Web Developer s/Application Sent d/20-Oct-2022 10:00 l/Java e/metaHires@meta.com`
+What you will see:
-Adds a person to the address book.
+| What you will see |
+|:------------------------------------------------:|
+| ![AddCommandResult](images/AddCommandResult.png) |
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
-
:bulb: **Tip:**
-A person can have any number of tags (including 0)
+
+**:bulb: Tip:** The date and time you provide could represent multiple things:
+ * The date and time it happened
+ * The deadline of the corresponding `Stage`
+**:exclamation: Caution**
+* adding DateTime like `d/24-Sep-2022 24:00` will be read as `d/25-Sep-2022 00:00`
+
-### Listing all persons : `list`
+Other examples:
+* `add c/Shopback r/Blockchain Developer s/Technical Interview`
+* `add c/Bytedance r/Backend Engineer s/Online Assessment d/24-Sep-2022 15:00 t/high pay l/Java l/Python`
-Shows a list of all persons in the address book.
+### 5.2. Editing your internship application
-Format: `list`
+WorkBook allows you to seamlessly update fields of respective internship applications with this command.
+
+A good time to use this command is to update the stage of your application so that WorkBook can give you relevant tips and reminders!
+
+Format: `edit INDEX [c/COMPANY] [r/ROLE] [s/STAGE] [d/DATETIME] [e/COMPANY_EMAIL] [l/LANGUAGE TAG] [t/TAG]…`
+
+* Edits the internship at the specified `INDEX`, which **must be**:
+ * A positive number (1, 2, 3, …).
+ * Within the number range of your list of internship applications.
+* At least one of the optional fields **must** be provided.
-### Editing a person : `edit`
+Example: `edit 2 s/Technical Interview d/28-Dec-2022 08:00`
-Edits an existing person in the address book.
+What you'll see before and after executing the command:
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+| State | What you will see |
+|------------|---------------------------------------------|
+| **Before** | ![Before edit](images/EditCommandInput.png) |
+| **After** | ![After edit](images/EditCommandResult.png) |
-* 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
+
+
+**:exclamation: Caution**: Adding of tags is not cumulative: When editing tags, the existing tags of the internship will be **removed**.
+
+
+
+**:bulb: Tip:** As adding of tags is not cumulative, you can remove all the internship’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.
-* `edit 2 n/Betsy Crower t/` Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags.
+Other examples:
+* `edit 2 l/golang t/`: Adds `golang` as the only language tag for the second internship and clears all existing tags.
+
+### 5.3. Listing all existing internship applications
+
+Lists all of your internship applications in WorkBook in a [sorted order](#43-behaviour-of-sorted-internship-applications).
+
+
+**:bulb: Tip:** Your most recent upcoming internship application will be at the top of the list!
+
+
+Format: `list`
-### Locating persons by name: `find`
+### 5.4. Viewing tips for your applications:
-Finds persons whose names contain any of the given keywords.
+For some application stages, we have included a list of useful tips to help you prepare for and ace the deliverables.
-Format: `find KEYWORD [MORE_KEYWORDS]`
+Below are the application stages that we have included tips for.
-* The search is case-insensitive. e.g `hans` will match `Hans`
-* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans`
-* Only the name is searched.
-* Only full words will be matched e.g. `Han` will not match `Hans`
-* Persons matching at least one keyword will be returned (i.e. `OR` search).
- e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang`
+| Application Stage |
+|------------------------|
+| `Application Sent` |
+| `Online Assessment` |
+| `Technical Interview` |
+| `Behavioral Interview` |
+| `Phone Interview` |
+| `Rejected` |
+
+If WorkBook is in the [narrow layout](#44-responsive-ui-when-resizing-window), simply click on the light bulb icon to view the tips for that application. A window will appear showing all the tips for that application.
+
+| Light Bulb Button | Tips Window |
+|:-----------------------------------------------:|:-------------------------------------:|
+| ![light bulb button](images/ClickLightBulb.png) | ![tips window](images/TipsWindow.png) |
+
+To view the tips in the [wide layout](#44-responsive-ui-when-resizing-window), simply click and select the application you would like to view the tips for. The tips will appear in the right panel.
+
+### 5.5. Finding your internships
+
+If you wanted to view all your internship applications corresponding to a particular company, stage or role,
+then this command is for you!
+
+It can find internships whose company, role or stage names contain all the respective keywords.
+
+Format: `find c/COMPANY | r/ROLE | s/STAGE`
+
+* Displays a list of internships that match all the keywords.
+
+
+**:bulb: Tip:**
+* Case does not matter e.g. `meta` will match `Meta`.
+* Order of the keywords does not matter e.g. `Jane Street` will match `Street Jane`.
+
+
+
+**:exclamation: Caution**
+* Only full words will be matched e.g. `met` will not match `Meta`.
+* Exactly one attribute can be searched for either Company, Role or Stage.
+* If you input keywords for more than one prefix it will result in an invalid command e.g. `find c/Meta s/Interview` will not be accepted
+
+
+
+
Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png)
+* `find r/Engineer` returns `Software Engineer` and `Backend Engineer`:
+
+| Before | After |
+|:-------------------------------------------:|:-----------------------------------------:|
+| ![before layout](images/BeforeFindRole.png) | ![after layout](images/AfterFindRole.png) |
+
-### Deleting a person : `delete`
+### 5.6. Deleting your internship application
-Deletes the specified person from the address book.
+If you want to remove an internship application then this command
+deletes the specified internship application from WorkBook.
Format: `delete INDEX`
-* Deletes 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, …
+* Deletes the internship at the specified `INDEX`, which **must be**:
+ * A positive number (1, 2, 3, …).
+ * Within the number range of your list of internship applications.
Examples:
-* `list` followed by `delete 2` deletes the 2nd person in the address book.
-* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command.
+* `list` followed by `delete 2` deletes the 2nd internship application in WorkBook.
+* `find Meta` followed by `delete 1` deletes the 1st internship application within the results of the `find` command.
-### Clearing all entries : `clear`
+### 5.7. Clearing your existing internship applications
-Clears all entries from the address book.
+Be it getting ready for a new internship application cycle or wanting to do a general spring-cleaning of your
+list of internship applications in WorkBook, this command is the one for you!
+
+Use this command to clear all the applications you've previously saved in WorkBook.
Format: `clear`
-### Exiting the program : `exit`
+Example:
+* `clear` removes all internship applications in the WorkBook.
+
+
+**:bulb: Tip:** If you cleared your internship applications by mistake, fret not as you can easily undo this!
+
+
+### 5.8. Undoing your previous command
+
+What if you accidentally made a mistake and performed a wrong undoable command?
+Workbook can help you to undo your changes after performing an
+undesirable undoable command and restore itself to the
+previous version!
+
+WorkBook keeps track of all your previous undoable commands and its current version, allowing you to `undo` as many times
+to restore any desired state of your WorkBook.
+
+Format: `undo`
+* Undo the previous undoable command.
+* You can perform the `undo` command as many times as the number of tracked Workbook versions
+i.e. stacking 2 undo commands sequentially will revert the WorkBook back 2
+versions ago, assuming you performed at least 2 undoable commands previously!
+* When you perform an undoable command, it will be stacked on top of the
+previous undoable command in the stack. The `undo` command will undo the first undoable command at the
+top of the stack.
+
+* If you have not executed an undoable command previously, the WorkBook will remain in its current version
+and return an error message: "No previous changes to undo!".
+
+![UndoFailure](images/UndoFailure.png)
+
+
+
+**:information_source: Note:**
+You can only undo undoable commands!
+* `add`
+* `edit`
+* `delete`
+* `clear`
+* `redo`
+
+
+Examples:
+* `add c/Meta r/Frontend Engineer s/Application Sent d/29-Oct-2022 12:00 e/hrmonkey@example.com` followed by `undo` will
+display the WorkBook version without the added internship.
+* `edit 1 s/Behavioural Interview e/hr@meta.com` followed by `clear` and then `undo` will undo the
+clearing of the Workbook. The edited stage and email address of the first internship will remain in the
+displayed WorkBook version.
+* `delete 2` followed by `list` and then `undo` will restore the WorkBook to its version prior to the
+`delete 2` command as the `list` command is not an undoable command and does not create a new
+version of the WorkBook.
+* `edit 2 l/golang t/` followed by `delete 1` and then 2 consecutive `undo` commands will first restore the
+WorkBook to its version before the `delete 1` command, and then the version before the `edit` command.
+
+What you'll see before and after executing the command:
+
+| State | What you will see |
+|--------------------------------------------------|----------------------------------------|
+| **Before** | ![BeforeEdit](images/BeforeEdit.png) |
+| **After executing command `edit 2 l/golang t/`** | ![AfterEdit](images/AfterEdit.png) |
+| **After executing command `delete 1`** | ![AfterDelete](images/AfterDelete.png) |
+| **After executing command: `undo`** | ![AfterUndo1](images/AfterUndo1.png) |
+| **After executing command: `undo`** | ![AfterUndo2](images/AfterUndo2.png) |
+
+
+
+**:bulb: Tip:**
+* If you have undone your previous undoable command by mistake, fret not as you can easily redo this
+to reapply the initial changes!
+* Performing multiple `undo` commands may confuse you as to which undoable command you are
+undoing and how your WorkBook currently looks like!
+* Tracked WorkBook versions will reset once you `exit` the application!
+
+
+
+### 5.9. Redoing your previous command
+
+Now, what if you mistakenly performed an `undo` command?
+Workbook can help you to redo your changes after performing
+an undesirable `undo` command and restore itself to the version before that!
+
+WorkBook keeps track of all your previous undoable commands and its current version,
+allowing the `redo` command to be performed as many times to reverse the
+`undo` commands you have performed!
+
+Format: `redo`
+* Redo the previous `undo` command.
+* You can perform the redo command as many times as the number of undone versions in the Workbook's tracked versions
+i.e. stacking 2 redo commands sequentially will revert the WorkBook back to its version 2
+ `undo` commands ago, assuming that you performed at least 2 `undo` commands previously.
+* When you perform an `undo` command, it will be stacked on top of the
+previous `undo` command in the stack. The `redo` command will redo the first `undo` command at the
+top of the stack.
+* If you have not executed a previous `undo` command, the WorkBook will remain in its current state
+ and return an error message: "No more commands to redo!".
+
+![RedoFailure](images/RedoFailure.png)
+
+Examples:
+* `add c/Meta r/Frontend Engineer s/Application Sent d/29-Oct-2022 12:00 e/hrmonkey@example.com` followed by `undo`
+and then `redo` will restore the WorkBook version with the added internship.
+* `edit 1 s/Behavioural Interview e/hr@visa.com` followed by `clear` will create 2 new WorkBook versions.
+If you perform 2 consecutive `undo` commands, the WorkBook will be restored to the version before both
+`edit` and `clear` commands. When you perform a `redo` command now,
+the WorkBook version will contain the edited stage and email for the first internship.
+
+
+
+
+| State | What you will see |
+|----------------------------------------------------------------------------|------------------------------------------|
+| **After executing command `edit 1 s/Behavioural Interview e/hr@visa.com`** | ![AfterEdit](images/RedoAfterEdit.png) |
+| **After executing command `clear`** | ![AfterClear](images/RedoAfterClear.png) |
+| **After executing command: `undo`** | ![AfterUndo1](images/RedoAfterUndo1.png) |
+| **After executing command: `undo`** | ![AfterUndo2](images/RedoAfterUndo2.png) |
+| **After executing command: `redo`** | ![AfterRedo](images/RedoAfterRedo.png) |
+
+
+
+**:bulb: Tip:**
+* If you have redone your previous undo command by mistake, fret not as you can easily undo this again
+to remove the initial changes!
+* Performing multiple `redo` commands may confuse you as to which `undo` command you are
+redoing and how your WorkBook currently looks like!
+* Tracked WorkBook versions will reset once you `exit` the application!
+
+
+### 5.10. Viewing help
+
+This shows a summary of the commands as well as a link to this User Guide.
+
+Format: `help`
+
+### 5.11. Exiting the program
Exits the program.
Format: `exit`
-### Saving the data
+--------------------------------------------------------------------------------------------------------------------
+
+## 6. Managing your data
+
+### 6.1. Saving
+
+Conveniently, any inputted command that changes any part of your internship application is **automatically saved**!
+Hence, you need not worry about pressing ctrl + s on your keyboard everytime you update your list of internship applications.
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+### 6.2. Editing
-### Editing the data file
+All of your internship applications are saved in a JSON file under the `data` subfolder.
+You are free to update any internship application directly by editing that JSON file.
-AddressBook data are saved as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
+
+
+**:information_source: JSON?:**
+* JSON stands for JavaScript Object Notation, learn how to edit the file [here](https://www.softwaretestinghelp.com/how-to-open-a-json-file/)!
+
+
:exclamation: **Caution:**
-If your changes to the data file makes its format invalid, AddressBook will discard all data and start with an empty data file at the next run.
+If your changes to the data file makes its format invalid, WorkBook will discard all data and start with an empty data file at the next run.
-### Archiving data files `[coming in v2.0]`
+--------------------------------------------------------------------------------------------------------------------
+
+## 7. Frequently asked questions
+
+**Q**: How do I transfer my data to another Computer?
+**A**: [Install](#2-get-started) the app in the other computer, copy and override the JSON file in the new `data` subfolder, and you are done!
-_Details coming soon ..._
+**Q**: How do I change the theme of WorkBook?
+**A**: It is not possible as of now, but will be coming soon!
--------------------------------------------------------------------------------------------------------------------
-## FAQ
+## 8. Prefix summary
-**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 AddressBook home folder.
+| Prefix | Symbolizes |
+|--------|--------------|
+| **n/** | Company Name |
+| **s/** | Stage |
+| **r/** | Role |
+| **d/** | DateTime |
+| **e/** | Email |
+| **l/** | Language Tag |
+| **t/** | Tag |
--------------------------------------------------------------------------------------------------------------------
-## Command summary
-
-Action | Format, Examples
---------|------------------
-**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`
-**List** | `list`
-**Help** | `help`
+## 9. Glossary
+
+| Term | Description |
+|--------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|
+| Graphical User Interface (GUI) | GUI allows user to interact with an application through graphics such as icons, menu, etc. |
+| Command Line Interface (CLI) | CLI allows user to use text as commands to be executed by an application. |
+| Command | Instruction typed by the user for WorkBook to execute. |
+| Parameter | A component of a command for the user to input information. For WorkBook's context, this refers to the internship application details. |
+| Prefix | An abbreviation for the name of the parameter. Prefix should be entered before the actual parameter in a command and always ends with a slash (/). |
+| Alphanumeric | Characters that are either a number or a letter. |
+| Subfolder | A folder within a folder. |
+
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..f89a3c8a47c 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,4 +1,4 @@
-title: "AB-3"
+title: "WorkBook"
theme: minima
header_pages:
@@ -8,7 +8,12 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+# Solution reused from https://github.com/AY2021S1-CS2103T-W16-3/tp/pull/179/commits/aec461182c194c9ca2c67d7c407fcabb376191ff
+kramdown:
+ parse_block_html: true
+
+
+repository: "AY2223S1-CS2103T-T10-3/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..14f69525d72 100644
--- a/docs/_sass/minima/_base.scss
+++ b/docs/_sass/minima/_base.scss
@@ -288,7 +288,7 @@ table {
text-align: center;
}
.site-header:before {
- content: "AB-3";
+ content: "WorkBook";
font-size: 32px;
}
}
diff --git a/docs/_sass/minima/_layout.scss b/docs/_sass/minima/_layout.scss
index ca99f981701..272eee5d882 100644
--- a/docs/_sass/minima/_layout.scss
+++ b/docs/_sass/minima/_layout.scss
@@ -261,3 +261,11 @@
width: calc(50% - (#{$spacing-unit} / 2));
}
}
+
+/**
+ * Table of Contents with bullet points removed
+ * Reused from https://github.com/AY2021S1-CS2103T-W16-3/tp/pull/190/commits/b91ca546a6a41a977a8dbf4d40c969ab07a49ad7
+ */
+ .toc-no-bullet-points ul, .toc-no-bullet-points ol {
+ list-style-type: none;
+}
diff --git a/docs/diagrams/AddCommandClassDiagram.puml b/docs/diagrams/AddCommandClassDiagram.puml
new file mode 100644
index 00000000000..938f316f2c0
--- /dev/null
+++ b/docs/diagrams/AddCommandClassDiagram.puml
@@ -0,0 +1,44 @@
+@startuml
+!include style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor UI_COLOR_T4
+skinparam classBackgroundColor UI_COLOR
+show members
+
+package Model <>{
+Class "<>\nModel" as Model
+Class ModelManager
+Class VersionedWorkBook
+Class Internship
+Class UniqueInternshipList {
+internalList: ObservableList
+sortedInternalList: SortedList
+}
+Class WorkBook
+}
+
+package Logic {
+Class AddCommandParser {
+parse(String): AddCommand
+}
+Class AddCommand
+Class CommandResult
+Class "{abstract}\nCommand" as Command
+}
+
+Class HiddenOutside #FFFFFF
+HiddenOutside .> AddCommand
+
+AddCommandParser ..> AddCommand : produces >
+AddCommand -up-|> Command
+Command .> CommandResult : produces >
+
+Command ...> Model
+
+ModelManager .up.|> Model
+VersionedWorkBook -up-|> WorkBook
+ModelManager --> "1 " VersionedWorkBook
+
+WorkBook *--> "1 " UniqueInternshipList
+UniqueInternshipList --> "~* all" Internship
+@enduml
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
index ef81d18c337..b91b2dbda00 100644
--- a/docs/diagrams/ArchitectureSequenceDiagram.puml
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -13,13 +13,13 @@ activate ui UI_COLOR
ui -[UI_COLOR]> logic : execute("delete 1")
activate logic LOGIC_COLOR
-logic -[LOGIC_COLOR]> model : deletePerson(p)
+logic -[LOGIC_COLOR]> model : deleteInternship(1)
activate model MODEL_COLOR
model -[MODEL_COLOR]-> logic
deactivate model
-logic -[LOGIC_COLOR]> storage : saveAddressBook(addressBook)
+logic -[LOGIC_COLOR]> storage : saveWorkBook(WorkBook)
activate storage STORAGE_COLOR
storage -[STORAGE_COLOR]> storage : Save to file
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
index 5731f9cbaa1..bc443f07ff9 100644
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ b/docs/diagrams/BetterModelClassDiagram.puml
@@ -4,18 +4,21 @@ skinparam arrowThickness 1.1
skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
-AddressBook *-right-> "1" UniquePersonList
-AddressBook *-right-> "1" UniqueTagList
-UniqueTagList -[hidden]down- UniquePersonList
-UniqueTagList -[hidden]down- UniquePersonList
+WorkBook *-right-> "1" UniqueInternshipList
+WorkBook *-right-> "1" UniqueTagList
+UniqueTagList -[hidden]down- UniqueInternshipList
+UniqueTagList -[hidden]down- UniqueInternshipList
UniqueTagList *-right-> "*" Tag
-UniquePersonList -right-> Person
+UniqueInternshipList -right-> Internship
+
+Internship -up-> "*" Tag
+
+Internship *--> Company
+Internship *--> Role
+Internship *--> Email
+Internship *--> Stage
+Internship *--> DateTime
-Person -up-> "*" Tag
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
@enduml
diff --git a/docs/diagrams/CommitActivityDiagram.puml b/docs/diagrams/CommitActivityDiagram.puml
index 6a6b23a006f..8d5b06de90c 100644
--- a/docs/diagrams/CommitActivityDiagram.puml
+++ b/docs/diagrams/CommitActivityDiagram.puml
@@ -1,14 +1,15 @@
@startuml
+
+skinparam ActivityBackgroundColor yellow
start
:User executes command;
'Since the beta syntax does not support placing the condition outside the
'diamond we place it as the true branch instead.
-if () then ([command commits AddressBook])
- :Purge redundant states;
- :Save AddressBook to
- addressBookStateList;
+if () then ([command commits WorkBook])
+ :Purge redundant states;
+ :Save WorkBook to workBookStateList;
else ([else])
endif
stop
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 1dc2311b245..9ffb2717a56 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -3,7 +3,7 @@
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":WorkBookParser" as AddressBookParser LOGIC_COLOR
participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR
participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR
participant ":CommandResult" as CommandResult LOGIC_COLOR
@@ -48,7 +48,7 @@ deactivate AddressBookParser
LogicManager -> DeleteCommand : execute()
activate DeleteCommand
-DeleteCommand -> Model : deletePerson(1)
+DeleteCommand -> Model : deleteInternship(1)
activate Model
Model --> DeleteCommand
diff --git a/docs/diagrams/FindCommandDiagram.puml b/docs/diagrams/FindCommandDiagram.puml
new file mode 100644
index 00000000000..4e3db8fc295
--- /dev/null
+++ b/docs/diagrams/FindCommandDiagram.puml
@@ -0,0 +1,44 @@
+@startuml
+!include style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor UI_COLOR_T4
+skinparam classBackgroundColor UI_COLOR
+show members
+
+package Model <>{
+Class "<>\nModel" as Model
+Class ModelManager
+Class VersionedWorkBook
+Class Internship
+Class UniqueInternshipList {
+internalList: ObservableList
+sortedInternalList: SortedList
+}
+Class WorkBook
+}
+
+package Logic {
+Class FindCommandParser {
+parse(String): FindCommand
+}
+Class FindCommand
+Class CommandResult
+Class "{abstract}\nCommand" as Command
+}
+
+Class HiddenOutside #FFFFFF
+HiddenOutside .> FindCommand
+
+FindCommandParser ..> FindCommand : produces >
+FindCommand -up-|> Command
+Command .> CommandResult : produces >
+
+Command ...> Model
+
+ModelManager .up.|> Model
+VersionedWorkBook -up-|> WorkBook
+ModelManager --> "1 " VersionedWorkBook
+
+WorkBook *--> "1 " UniqueInternshipList
+UniqueInternshipList --> "~* all" Internship
+@enduml
diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml
index d4193173e18..ba4f8a25c70 100644
--- a/docs/diagrams/LogicClassDiagram.puml
+++ b/docs/diagrams/LogicClassDiagram.puml
@@ -6,7 +6,7 @@ skinparam classBackgroundColor LOGIC_COLOR
package Logic {
-Class AddressBookParser
+Class WorkBookParser
Class XYZCommand
Class CommandResult
Class "{abstract}\nCommand" as Command
@@ -27,8 +27,8 @@ Class HiddenOutside #FFFFFF
HiddenOutside ..> Logic
LogicManager .right.|> Logic
-LogicManager -right->"1" AddressBookParser
-AddressBookParser ..> XYZCommand : creates >
+LogicManager -right->"1" WorkBookParser
+WorkBookParser ..> XYZCommand : creates >
XYZCommand -up-|> Command
LogicManager .left.> Command : executes >
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 4439108973a..7dc857b4ff2 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -5,19 +5,20 @@ skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
Package Model <>{
-Class "<>\nReadOnlyAddressBook" as ReadOnlyAddressBook
+Class "<>\nReadOnlyWorkBook" as ReadOnlyWorkBook
Class "<>\nReadOnlyUserPrefs" as ReadOnlyUserPrefs
Class "<>\nModel" as Model
-Class AddressBook
+Class WorkBook
Class ModelManager
Class UserPrefs
-Class UniquePersonList
-Class Person
-Class Address
+Class UniqueInternshipList
+Class Internship
+Class Company
+Class DateTime
+Class Role
+Class Stage
Class Email
-Class Name
-Class Phone
Class Tag
}
@@ -25,26 +26,27 @@ Class Tag
Class HiddenOutside #FFFFFF
HiddenOutside ..> Model
-AddressBook .up.|> ReadOnlyAddressBook
+WorkBook .up.|> ReadOnlyWorkBook
ModelManager .up.|> Model
Model .right.> ReadOnlyUserPrefs
-Model .left.> ReadOnlyAddressBook
-ModelManager -left-> "1" AddressBook
+Model .left.> ReadOnlyWorkBook
+ModelManager -left-> "1" WorkBook
ModelManager -right-> "1" UserPrefs
UserPrefs .up.|> ReadOnlyUserPrefs
-AddressBook *--> "1" UniquePersonList
-UniquePersonList --> "~* all" Person
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-Person *--> "*" Tag
+WorkBook *--> "1" UniqueInternshipList
+UniqueInternshipList --> "~* all" Internship
+Internship *--> Company
+Internship *--> DateTime
+Internship *--> Role
+Internship *--> Stage
+Internship *--> Email
+Internship *--> "*" Tag
-Name -[hidden]right-> Phone
-Phone -[hidden]right-> Address
-Address -[hidden]right-> Email
+Company -[hidden]right-> Role
+Role -[hidden]right-> Stage
+Stage -[hidden]right-> DateTime
-ModelManager -->"~* filtered" Person
+ModelManager -->"~* filtered" Internship
@enduml
diff --git a/docs/diagrams/ParserClasses.puml b/docs/diagrams/ParserClasses.puml
index 0c7424de6e0..bf317f91c46 100644
--- a/docs/diagrams/ParserClasses.puml
+++ b/docs/diagrams/ParserClasses.puml
@@ -9,7 +9,7 @@ Class XYZCommand
package "Parser classes"{
Class "<>\nParser" as Parser
-Class AddressBookParser
+Class WorkBookParser
Class XYZCommandParser
Class CliSyntax
Class ParserUtil
@@ -19,12 +19,12 @@ Class Prefix
}
Class HiddenOutside #FFFFFF
-HiddenOutside ..> AddressBookParser
+HiddenOutside ..> WorkBookParser
-AddressBookParser .down.> XYZCommandParser: creates >
+WorkBookParser .down.> XYZCommandParser: creates >
XYZCommandParser ..> XYZCommand : creates >
-AddressBookParser ..> Command : returns >
+WorkBookParser ..> Command : returns >
XYZCommandParser .up.|> Parser
XYZCommandParser ..> ArgumentMultimap
XYZCommandParser ..> ArgumentTokenizer
diff --git a/docs/diagrams/RedoSequenceDiagram.puml b/docs/diagrams/RedoSequenceDiagram.puml
new file mode 100644
index 00000000000..09ef6881267
--- /dev/null
+++ b/docs/diagrams/RedoSequenceDiagram.puml
@@ -0,0 +1,53 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":WorkBookParser" as WorkBookParser LOGIC_COLOR
+participant "r:RedoCommand" as RedoCommand LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+participant ":VersionedWorkBook" as VersionedWorkBook MODEL_COLOR
+end box
+[-> LogicManager : execute(redo)
+activate LogicManager
+
+LogicManager -> WorkBookParser : parseCommand(redo)
+activate WorkBookParser
+
+create RedoCommand
+WorkBookParser -> RedoCommand
+activate RedoCommand
+
+RedoCommand --> WorkBookParser
+deactivate RedoCommand
+
+WorkBookParser --> LogicManager : r
+deactivate WorkBookParser
+
+LogicManager -> RedoCommand : execute()
+activate RedoCommand
+
+RedoCommand -> Model : redoWorkBook()
+activate Model
+
+Model -> VersionedWorkBook : redo()
+activate VersionedWorkBook
+
+VersionedWorkBook -> VersionedWorkBook :resetData(ReadOnlyWorkBook)
+VersionedWorkBook --> Model :
+deactivate VersionedWorkBook
+
+Model --> RedoCommand
+deactivate Model
+
+RedoCommand --> LogicManager : result
+deactivate RedoCommand
+RedoCommand -[hidden]-> LogicManager : result
+destroy RedoCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index 760305e0e58..f6fdd08d43e 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -14,11 +14,11 @@ Class JsonUserPrefsStorage
Class "<>\nStorage" as Storage
Class StorageManager
-package "AddressBook Storage" #F4F6F6{
-Class "<>\nAddressBookStorage" as AddressBookStorage
-Class JsonAddressBookStorage
-Class JsonSerializableAddressBook
-Class JsonAdaptedPerson
+package "Workbook Storage" #F4F6F6{
+Class "<>\nWorkBookStorage" as WorkBookStorage
+Class JsonWorkBookStorage
+Class JsonSerializableWorkBook
+Class JsonAdaptedInternship
Class JsonAdaptedTag
}
@@ -29,15 +29,15 @@ HiddenOutside ..> Storage
StorageManager .up.|> Storage
StorageManager -up-> "1" UserPrefsStorage
-StorageManager -up-> "1" AddressBookStorage
+StorageManager -up-> "1" WorkBookStorage
Storage -left-|> UserPrefsStorage
-Storage -right-|> AddressBookStorage
+Storage -right-|> WorkBookStorage
JsonUserPrefsStorage .up.|> UserPrefsStorage
-JsonAddressBookStorage .up.|> AddressBookStorage
-JsonAddressBookStorage ..> JsonSerializableAddressBook
-JsonSerializableAddressBook --> "*" JsonAdaptedPerson
-JsonAdaptedPerson --> "*" JsonAdaptedTag
+JsonWorkBookStorage .up.|> WorkBookStorage
+JsonWorkBookStorage ..> JsonSerializableWorkBook
+JsonSerializableWorkBook --> "*" JsonAdaptedInternship
+JsonAdaptedInternship --> "*" JsonAdaptedTag
@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 95473d5aa19..8544800ec40 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -11,8 +11,8 @@ Class UiManager
Class MainWindow
Class HelpWindow
Class ResultDisplay
-Class PersonListPanel
-Class PersonCard
+Class InternshipListPanel
+Class InternshipCard
Class StatusBarFooter
Class CommandBox
}
@@ -32,26 +32,26 @@ UiManager .left.|> Ui
UiManager -down-> "1" MainWindow
MainWindow *-down-> "1" CommandBox
MainWindow *-down-> "1" ResultDisplay
-MainWindow *-down-> "1" PersonListPanel
+MainWindow *-down-> "1" InternshipListPanel
MainWindow *-down-> "1" StatusBarFooter
MainWindow --> "0..1" HelpWindow
-PersonListPanel -down-> "*" PersonCard
+InternshipListPanel -down-> "*" InternshipCard
MainWindow -left-|> UiPart
ResultDisplay --|> UiPart
CommandBox --|> UiPart
-PersonListPanel --|> UiPart
-PersonCard --|> UiPart
+InternshipListPanel --|> UiPart
+InternshipCard --|> UiPart
StatusBarFooter --|> UiPart
HelpWindow --|> UiPart
-PersonCard ..> Model
+InternshipCard ..> Model
UiManager -right-> Logic
MainWindow -left-> Logic
-PersonListPanel -[hidden]left- HelpWindow
+InternshipListPanel -[hidden]left- HelpWindow
HelpWindow -[hidden]left- CommandBox
CommandBox -[hidden]left- ResultDisplay
ResultDisplay -[hidden]left- StatusBarFooter
diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/UndoRedoState0.puml
index 96e30744d24..b65cc413135 100644
--- a/docs/diagrams/UndoRedoState0.puml
+++ b/docs/diagrams/UndoRedoState0.puml
@@ -6,15 +6,15 @@ skinparam ClassBorderColor #000000
title Initial state
package States {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "__ab0:WorkBook__"
+ class State2 as "__ab1:WorkBook__"
+ class State3 as "__ab2:WorkBook__"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
hide State2
hide State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State"
Pointer -up-> State1
@end
diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml
index 01fcb9b2b96..93f533da3ef 100644
--- a/docs/diagrams/UndoRedoState1.puml
+++ b/docs/diagrams/UndoRedoState1.puml
@@ -6,9 +6,9 @@ skinparam ClassBorderColor #000000
title After command "delete 5"
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "__ab0:WorkBook__"
+ class State2 as "__ab1:WorkBook__"
+ class State3 as "__ab2:WorkBook__"
}
State1 -[hidden]right-> State2
@@ -16,7 +16,7 @@ State2 -[hidden]right-> State3
hide State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State"
Pointer -up-> State2
@end
diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml
index bccc230a5d1..2fbdc3805df 100644
--- a/docs/diagrams/UndoRedoState2.puml
+++ b/docs/diagrams/UndoRedoState2.puml
@@ -3,18 +3,18 @@
skinparam ClassFontColor #000000
skinparam ClassBorderColor #000000
-title After command "add n/David"
+title After command "add..."
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "__ab0:WorkBook__"
+ class State2 as "__ab1:WorkBook__"
+ class State3 as "__ab2:WorkBook__"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State"
Pointer -up-> State3
@end
diff --git a/docs/diagrams/UndoRedoState3.puml b/docs/diagrams/UndoRedoState3.puml
index ea29c9483e4..8c44a969e01 100644
--- a/docs/diagrams/UndoRedoState3.puml
+++ b/docs/diagrams/UndoRedoState3.puml
@@ -6,15 +6,15 @@ skinparam ClassBorderColor #000000
title After command "undo"
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "__ab0:WorkBook__"
+ class State2 as "__ab1:WorkBook__"
+ class State3 as "__ab2:WorkBook__"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State"
Pointer -up-> State2
@end
diff --git a/docs/diagrams/UndoRedoState4.puml b/docs/diagrams/UndoRedoState4.puml
index 1b784cece80..aec3b309ee2 100644
--- a/docs/diagrams/UndoRedoState4.puml
+++ b/docs/diagrams/UndoRedoState4.puml
@@ -3,18 +3,18 @@
skinparam ClassFontColor #000000
skinparam ClassBorderColor #000000
-title After command "list"
+title After command "redo"
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "__ab0:WorkBook__"
+ class State2 as "__ab1:WorkBook__"
+ class State3 as "__ab2:WorkBook__"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State"
-Pointer -up-> State2
+Pointer -up-> State3
@end
diff --git a/docs/diagrams/UndoRedoState5.puml b/docs/diagrams/UndoRedoState5.puml
index 88927be32bc..358e2fe7b03 100644
--- a/docs/diagrams/UndoRedoState5.puml
+++ b/docs/diagrams/UndoRedoState5.puml
@@ -3,19 +3,18 @@
skinparam ClassFontColor #000000
skinparam ClassBorderColor #000000
-title After command "clear"
+title After command "list"
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab3:AddressBook__"
+ class State1 as "__ab0:WorkBook__"
+ class State2 as "__ab1:WorkBook__"
+ class State3 as "__ab2:WorkBook__"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State"
-Pointer -up-> State3
-note right on link: State ab2 deleted.
+Pointer -up-> State2
@end
diff --git a/docs/diagrams/UndoRedoState6.puml b/docs/diagrams/UndoRedoState6.puml
new file mode 100644
index 00000000000..d9c98be4a26
--- /dev/null
+++ b/docs/diagrams/UndoRedoState6.puml
@@ -0,0 +1,21 @@
+@startuml
+!include style.puml
+skinparam ClassFontColor #000000
+skinparam ClassBorderColor #000000
+
+title After command "clear"
+
+package States <> {
+ class State1 as "__ab0:WorkBook__"
+ class State2 as "__ab1:WorkBook__"
+ class State3 as "__ab3:WorkBook__"
+}
+
+State1 -[hidden]right-> State2
+State2 -[hidden]right-> State3
+
+class Pointer as "Current State"
+
+Pointer -up-> State3
+note right on link: State ab2 deleted.
+@end
diff --git a/docs/diagrams/UndoSequenceDiagram.puml b/docs/diagrams/UndoSequenceDiagram.puml
index 410aab4e412..15bb723eb91 100644
--- a/docs/diagrams/UndoSequenceDiagram.puml
+++ b/docs/diagrams/UndoSequenceDiagram.puml
@@ -3,42 +3,42 @@
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":WorkBookParser" as WorkBookParser LOGIC_COLOR
participant "u:UndoCommand" as UndoCommand LOGIC_COLOR
end box
box Model MODEL_COLOR_T1
participant ":Model" as Model MODEL_COLOR
-participant ":VersionedAddressBook" as VersionedAddressBook MODEL_COLOR
+participant ":VersionedWorkBook" as VersionedWorkBook MODEL_COLOR
end box
[-> LogicManager : execute(undo)
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand(undo)
-activate AddressBookParser
+LogicManager -> WorkBookParser : parseCommand(undo)
+activate WorkBookParser
create UndoCommand
-AddressBookParser -> UndoCommand
+WorkBookParser -> UndoCommand
activate UndoCommand
-UndoCommand --> AddressBookParser
+UndoCommand --> WorkBookParser
deactivate UndoCommand
-AddressBookParser --> LogicManager : u
-deactivate AddressBookParser
+WorkBookParser --> LogicManager : u
+deactivate WorkBookParser
LogicManager -> UndoCommand : execute()
activate UndoCommand
-UndoCommand -> Model : undoAddressBook()
+UndoCommand -> Model : undoWorkBook()
activate Model
-Model -> VersionedAddressBook : undo()
-activate VersionedAddressBook
+Model -> VersionedWorkBook : undo()
+activate VersionedWorkBook
-VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook)
-VersionedAddressBook --> Model :
-deactivate VersionedAddressBook
+VersionedWorkBook -> VersionedWorkBook :resetData(ReadOnlyWorkBook)
+VersionedWorkBook --> Model :
+deactivate VersionedWorkBook
Model --> UndoCommand
deactivate Model
diff --git a/docs/images/AddCommandClassDiagram.png b/docs/images/AddCommandClassDiagram.png
new file mode 100644
index 00000000000..15787e43b24
Binary files /dev/null and b/docs/images/AddCommandClassDiagram.png differ
diff --git a/docs/images/AddCommandResult.png b/docs/images/AddCommandResult.png
new file mode 100644
index 00000000000..0f9fd0e9402
Binary files /dev/null and b/docs/images/AddCommandResult.png differ
diff --git a/docs/images/AfterDelete.png b/docs/images/AfterDelete.png
new file mode 100644
index 00000000000..8265d1e4802
Binary files /dev/null and b/docs/images/AfterDelete.png differ
diff --git a/docs/images/AfterEdit.png b/docs/images/AfterEdit.png
new file mode 100644
index 00000000000..cd3f11640d3
Binary files /dev/null and b/docs/images/AfterEdit.png differ
diff --git a/docs/images/AfterFindRole.png b/docs/images/AfterFindRole.png
new file mode 100644
index 00000000000..2c65d52cc7c
Binary files /dev/null and b/docs/images/AfterFindRole.png differ
diff --git a/docs/images/AfterRedoStack.png b/docs/images/AfterRedoStack.png
new file mode 100644
index 00000000000..4585b4a7731
Binary files /dev/null and b/docs/images/AfterRedoStack.png differ
diff --git a/docs/images/AfterUndo1.png b/docs/images/AfterUndo1.png
new file mode 100644
index 00000000000..d010d0b87b7
Binary files /dev/null and b/docs/images/AfterUndo1.png differ
diff --git a/docs/images/AfterUndo2.png b/docs/images/AfterUndo2.png
new file mode 100644
index 00000000000..e40317486b4
Binary files /dev/null and b/docs/images/AfterUndo2.png differ
diff --git a/docs/images/AfterUndoStack.png b/docs/images/AfterUndoStack.png
new file mode 100644
index 00000000000..02ef3bb4209
Binary files /dev/null and b/docs/images/AfterUndoStack.png differ
diff --git a/docs/images/AnnotatedUi.png b/docs/images/AnnotatedUi.png
new file mode 100644
index 00000000000..0fce15be828
Binary files /dev/null and b/docs/images/AnnotatedUi.png differ
diff --git a/docs/images/AnnotatedUiNarrow.png b/docs/images/AnnotatedUiNarrow.png
new file mode 100644
index 00000000000..05fd1e2ca21
Binary files /dev/null and b/docs/images/AnnotatedUiNarrow.png differ
diff --git a/docs/images/AnnotatedUiNarrowBulbOnly.png b/docs/images/AnnotatedUiNarrowBulbOnly.png
new file mode 100644
index 00000000000..f807230ba63
Binary files /dev/null and b/docs/images/AnnotatedUiNarrowBulbOnly.png differ
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
index 2f1346869d0..db4ed0390d9 100644
Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ
diff --git a/docs/images/BeforeEdit.png b/docs/images/BeforeEdit.png
new file mode 100644
index 00000000000..dcd7c000c5d
Binary files /dev/null and b/docs/images/BeforeEdit.png differ
diff --git a/docs/images/BeforeFindRole.png b/docs/images/BeforeFindRole.png
new file mode 100644
index 00000000000..4f0867a929a
Binary files /dev/null and b/docs/images/BeforeFindRole.png differ
diff --git a/docs/images/BeforeRedoStack.png b/docs/images/BeforeRedoStack.png
new file mode 100644
index 00000000000..4a0fc5a9ae1
Binary files /dev/null and b/docs/images/BeforeRedoStack.png differ
diff --git a/docs/images/BeforeUndoStack.png b/docs/images/BeforeUndoStack.png
new file mode 100644
index 00000000000..326ea029194
Binary files /dev/null and b/docs/images/BeforeUndoStack.png differ
diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png
index 1ec62caa2a5..1bf9821d9b3 100644
Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ
diff --git a/docs/images/ClickLightBulb.png b/docs/images/ClickLightBulb.png
new file mode 100644
index 00000000000..d704f42c0f0
Binary files /dev/null and b/docs/images/ClickLightBulb.png differ
diff --git a/docs/images/CommitActivityDiagram.png b/docs/images/CommitActivityDiagram.png
index c08c13f5c8b..5d684e02aa4 100644
Binary files a/docs/images/CommitActivityDiagram.png and b/docs/images/CommitActivityDiagram.png differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
index fa327b39618..58c3582268f 100644
Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ
diff --git a/docs/images/EditCommandInput.png b/docs/images/EditCommandInput.png
new file mode 100644
index 00000000000..b8a6826e363
Binary files /dev/null and b/docs/images/EditCommandInput.png differ
diff --git a/docs/images/EditCommandResult.png b/docs/images/EditCommandResult.png
new file mode 100644
index 00000000000..2f4d6314fd2
Binary files /dev/null and b/docs/images/EditCommandResult.png differ
diff --git a/docs/images/FindCommandDiagram.png b/docs/images/FindCommandDiagram.png
new file mode 100644
index 00000000000..267524e7ce3
Binary files /dev/null and b/docs/images/FindCommandDiagram.png differ
diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png
index 9e9ba9f79e5..804a9c5794d 100644
Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png differ
diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png
index 04070af60d8..cf9497ede11 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/ParserClasses.png b/docs/images/ParserClasses.png
index e7b4c8880cd..a38d7d03653 100644
Binary files a/docs/images/ParserClasses.png and b/docs/images/ParserClasses.png differ
diff --git a/docs/images/RedoAfterClear.png b/docs/images/RedoAfterClear.png
new file mode 100644
index 00000000000..344cd2d7c24
Binary files /dev/null and b/docs/images/RedoAfterClear.png differ
diff --git a/docs/images/RedoAfterEdit.png b/docs/images/RedoAfterEdit.png
new file mode 100644
index 00000000000..29a7b8d0182
Binary files /dev/null and b/docs/images/RedoAfterEdit.png differ
diff --git a/docs/images/RedoAfterRedo.png b/docs/images/RedoAfterRedo.png
new file mode 100644
index 00000000000..a29a7f28711
Binary files /dev/null and b/docs/images/RedoAfterRedo.png differ
diff --git a/docs/images/RedoAfterUndo1.png b/docs/images/RedoAfterUndo1.png
new file mode 100644
index 00000000000..75184aa5246
Binary files /dev/null and b/docs/images/RedoAfterUndo1.png differ
diff --git a/docs/images/RedoAfterUndo2.png b/docs/images/RedoAfterUndo2.png
new file mode 100644
index 00000000000..f6010a23d1a
Binary files /dev/null and b/docs/images/RedoAfterUndo2.png differ
diff --git a/docs/images/RedoFailure.png b/docs/images/RedoFailure.png
new file mode 100644
index 00000000000..fa4973b7a22
Binary files /dev/null and b/docs/images/RedoFailure.png differ
diff --git a/docs/images/RedoSequenceDiagram.png b/docs/images/RedoSequenceDiagram.png
new file mode 100644
index 00000000000..a0f9e609c6b
Binary files /dev/null and b/docs/images/RedoSequenceDiagram.png differ
diff --git a/docs/images/ResponsiveUi.gif b/docs/images/ResponsiveUi.gif
new file mode 100644
index 00000000000..60f72e6a47f
Binary files /dev/null and b/docs/images/ResponsiveUi.gif differ
diff --git a/docs/images/SortExample.png b/docs/images/SortExample.png
new file mode 100644
index 00000000000..50708d31d8a
Binary files /dev/null and b/docs/images/SortExample.png differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
index 2533a5c1af0..189e6a2bfc1 100644
Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ
diff --git a/docs/images/TipsPanel.png b/docs/images/TipsPanel.png
new file mode 100644
index 00000000000..e1546648414
Binary files /dev/null and b/docs/images/TipsPanel.png differ
diff --git a/docs/images/TipsWindow.png b/docs/images/TipsWindow.png
new file mode 100644
index 00000000000..3ab7711077a
Binary files /dev/null and b/docs/images/TipsWindow.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 5bd77847aa2..959b9a4308b 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/Ui2.png b/docs/images/Ui2.png
new file mode 100644
index 00000000000..b7cd4885d45
Binary files /dev/null and b/docs/images/Ui2.png differ
diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png
index 785e04dbab4..885cb4bc2e9 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/docs/images/UiNarrow.png b/docs/images/UiNarrow.png
new file mode 100644
index 00000000000..705fcc2e4b2
Binary files /dev/null and b/docs/images/UiNarrow.png differ
diff --git a/docs/images/UndoFailure.png b/docs/images/UndoFailure.png
new file mode 100644
index 00000000000..aee4e8ff06c
Binary files /dev/null and b/docs/images/UndoFailure.png differ
diff --git a/docs/images/UndoRedoState0.png b/docs/images/UndoRedoState0.png
index 8f7538cd884..2f5418b587d 100644
Binary files a/docs/images/UndoRedoState0.png and b/docs/images/UndoRedoState0.png differ
diff --git a/docs/images/UndoRedoState1.png b/docs/images/UndoRedoState1.png
index df9908d0948..c98bd31baf9 100644
Binary files a/docs/images/UndoRedoState1.png and b/docs/images/UndoRedoState1.png differ
diff --git a/docs/images/UndoRedoState2.png b/docs/images/UndoRedoState2.png
index 36519c1015b..72ee283bd03 100644
Binary files a/docs/images/UndoRedoState2.png and b/docs/images/UndoRedoState2.png differ
diff --git a/docs/images/UndoRedoState3.png b/docs/images/UndoRedoState3.png
index 19959d01712..88fbac7d134 100644
Binary files a/docs/images/UndoRedoState3.png and b/docs/images/UndoRedoState3.png differ
diff --git a/docs/images/UndoRedoState4.png b/docs/images/UndoRedoState4.png
index 4c623e4f2c5..a3fa3c4a204 100644
Binary files a/docs/images/UndoRedoState4.png and b/docs/images/UndoRedoState4.png differ
diff --git a/docs/images/UndoRedoState5.png b/docs/images/UndoRedoState5.png
index 84ad2afa6bd..c0094d44dff 100644
Binary files a/docs/images/UndoRedoState5.png and b/docs/images/UndoRedoState5.png differ
diff --git a/docs/images/UndoRedoState6.png b/docs/images/UndoRedoState6.png
new file mode 100644
index 00000000000..0907b6a9989
Binary files /dev/null and b/docs/images/UndoRedoState6.png differ
diff --git a/docs/images/UndoSequenceDiagram.png b/docs/images/UndoSequenceDiagram.png
index 6addcd3a8d9..0ec900adc25 100644
Binary files a/docs/images/UndoSequenceDiagram.png and b/docs/images/UndoSequenceDiagram.png differ
diff --git a/docs/images/adeearyaa.png b/docs/images/adeearyaa.png
new file mode 100644
index 00000000000..f89833af8e9
Binary files /dev/null and b/docs/images/adeearyaa.png differ
diff --git a/docs/images/glemenneo.png b/docs/images/glemenneo.png
new file mode 100644
index 00000000000..5a89dd29ea8
Binary files /dev/null and b/docs/images/glemenneo.png differ
diff --git a/docs/images/jacobkwan.png b/docs/images/jacobkwan.png
new file mode 100644
index 00000000000..cb41da9376b
Binary files /dev/null and b/docs/images/jacobkwan.png differ
diff --git a/docs/images/rylzxc.png b/docs/images/rylzxc.png
new file mode 100644
index 00000000000..a0e1540a66a
Binary files /dev/null and b/docs/images/rylzxc.png differ
diff --git a/docs/images/tienyu2000.png b/docs/images/tienyu2000.png
new file mode 100644
index 00000000000..e7a1d3c1ec8
Binary files /dev/null and b/docs/images/tienyu2000.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..fd9dabdda29 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,19 +1,26 @@
---
layout: page
-title: AddressBook Level-3
+title: WorkBook
---
-[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions)
-[![codecov](https://codecov.io/gh/se-edu/addressbook-level3/branch/master/graph/badge.svg)](https://codecov.io/gh/se-edu/addressbook-level3)
+[![Java CI](https://github.com/AY2223S1-CS2103T-T10-3/tp/actions/workflows/gradle.yml/badge.svg)](https://github.com/AY2223S1-CS2103T-T10-3/tp/actions/workflows/gradle.yml)
+[![codecov](https://codecov.io/gh/AY2223S1-CS2103T-T10-3/tp/branch/master/graph/badge.svg?token=K13DUI69HX)](https://codecov.io/gh/AY2223S1-CS2103T-T10-3/tp)
![Ui](images/Ui.png)
-**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
+* WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications.
-* If you are interested in using AddressBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
-* If you are interested about developing AddressBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
+* WorkBook (WB) is optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, WB can get your internship management tasks done faster than traditional GUI apps.
+
+* If you are interested in using WorkBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
+* If you are interested about developing WorkBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
-* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5)
+* Libraries used: [JavaFX](https://openjfx.io), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5).
+* This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
+* User Guide: Table of Contents with bullet points removed is reused from [@ianyong's team in 2020](https://github.com/AY2021S1-CS2103T-W16-3/tp/pull/190/commits/b91ca546a6a41a977a8dbf4d40c969ab07a49ad7).
+* Reused [code](https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110) from CS2103T-T10-4 to parse optional arguments.
+* Reused [code](https://github.com/se-edu/addressbook-level4/blob/master/src/main/java/seedu/address/model/VersionedAddressBook.java) from AddressBook-Level4
+
diff --git a/docs/team/adeearyaa.md b/docs/team/adeearyaa.md
new file mode 100644
index 00000000000..99d2608bf0c
--- /dev/null
+++ b/docs/team/adeearyaa.md
@@ -0,0 +1,51 @@
+---
+layout: page
+title: Adee Aryaa's Project Portfolio Page
+---
+
+## Project: WorkBook
+
+### Overview
+
+WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, WB can get your internship management tasks done faster than traditional GUI apps.
+
+### Summary of contributions
+
+#### Code contributed
+
+This displays my code contributions for the project: [RepoSense link](https://nus-cs2103-ay2223s1.github.io/tp-dashboard/?search=adeearyaa&breakdown=true)
+
+#### Enhancements implemented
+- New Feature: [Find](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/87): Added the find function which allows internships to be displayed and filtered according to keywords.
+- New Feature: [Standardized user's inputs](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/81): Converting the user's input for attributes to a standardized pascal case format.
+
+
+#### Contributions to User Guide
+- Added the Glossary.
+- Added the summary of prefixes.
+- Added the value proposition.
+- Improved the tone of the user guide to make it more appealing to readers.
+- Added boxes categorized according to tips, good to know and warning categories
+- PR for the addition of the features above: [User Guide Changes](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/150)
+- Added the implementation of the find command to the User Guide: [Find User Guide](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/97)
+- Added images to the user guide to make it more clear for users: [Images User Guide](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/164)
+
+#### Contributions to Developer Guide
+- Added user stories: [Update User Stories](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/31)
+- Added use cases: [Update Use Cases](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/75)
+- Added Find Command's implementation: [Find Command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/179)
+
+#### Contributions to team-based tasks
+- [Testing](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/81): Added attributes for internships and test code.
+- [Another example of adding test files](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/87/commits/f02d66f84d1029f6460cebe3fd6778676b394df2)
+- Refactoring attributes of AB3 : [Deleting Phone Attribute](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/64)
+- Refactoring attributes of AB3 : [Deleting address attribute](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/55)
+- Refactoring attributes of AB3 : [Making email field optional](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/66)
+
+#### Review/mentoring contributions
+- Reviewed a few PRs made by my teammates.
+- Merged a few PRs as well.
+
+#### Contributions beyond the project team
+- Reported an above average amount of bugs in the PE-D(12)
+- Asked questions on the forum which ended up helping others who were in the same situation.
diff --git a/docs/team/glemenneo.md b/docs/team/glemenneo.md
new file mode 100644
index 00000000000..bbce5deb073
--- /dev/null
+++ b/docs/team/glemenneo.md
@@ -0,0 +1,42 @@
+---
+layout: page
+title: Glemen Neo's Project Portfolio Page
+---
+
+## Project: WorkBook
+
+### Overview
+
+WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, WB can get your internship management tasks done faster than traditional GUI apps.
+
+### Summary of contributions
+
+- Principle UI/UX engineer, implemented almost all UI changes from AB3 to WB.
+
+#### Code contributed
+
+This displays my code contributions for the project: [RepoSense link](https://nus-cs2103-ay2223s1.github.io/tp-dashboard/?search=glemenneo&breakdown=true)
+
+#### Enhancements implemented
+
+- [Help Window](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/56): Redesigned Help window with summary of commands.
+- [Internship Card](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/88): Redesigned Internship card to better fit WB.
+- [Responsive UI](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/92): Implemented Responsive UI that switches between narrow and wide UI formats depending on window width.
+- [Narrow UI](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/88): Implemented the Tips window and Tips button for narrow UI format.
+- [Wide UI](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/92): Implemented the Tips panel for wide UI format.
+
+#### Contributions to User Guide
+
+- [Refactoring](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/30): Updated UG from AB3 to WB by refactoring to provide the skeleton for other to add on.
+- [Edit Command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/42): Added section on Edit command.
+- [Tips and Responsive UI](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/56): Added sections on and accessing Tips and Responsive UI.
+
+#### Contributions to Developer Guide
+
+- [User Stories and Use Cases](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/77): Added User Stories and Use Cases for Tips.
+- [Help Window](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/177): Added section on Help window.
+- [Tips and Responsive UI](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/169): Added section on Tips button, Tips window, Tips panel and Responsive UI.
+
+#### Contributions to team-based tasks
+
+- [Refactoring](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/30): Refactored UG from AB3 to WB by to provide the skeleton for other to add on.
diff --git a/docs/team/jacobkwan.md b/docs/team/jacobkwan.md
new file mode 100644
index 00000000000..cf4d637b6d1
--- /dev/null
+++ b/docs/team/jacobkwan.md
@@ -0,0 +1,44 @@
+---
+layout: page
+title: Jacob Kwan's Project Portfolio Page
+---
+
+## Project: WorkBook
+
+### Overview
+
+WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, WB can get your internship management tasks done faster than traditional GUI apps.
+
+#### Code contributed
+
+This displays my code contributions for the project: [RepoSense link](https://nus-cs2103-ay2223s1.github.io/tp-dashboard/?search=jacobkwan&breakdown=true)
+
+#### Enhancements implemented
+- [New Feature: Default WorkBook state of having internship applications sorted by date](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/83)
+- [New Feature: Adding Language Tags](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/89)
+
+#### Contributions to User Guide
+- Overall refinement of tone and structure
+- [Miscellaneous bug fixing](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/167)
+- [Usage of `delete`](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/38)
+- [Command summary](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/100/files)
+
+#### Contributions to Developer Guide
+- [Added instructions for manual testing](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/173)
+- NFRs
+- Glossary
+
+#### Contributions to team-based tasks
+- [Refactoring](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/53): Changed project structure, class names and variable names to fit our product.
+- Documentation: Utilised local Jekyll server to improve iteration speed for everyone
+ - Instead of merging and deploying buggy/incorrectly formatted markdown, I can simply checkout teammates' branches to verify the correctness of more complex markdown elements
+ - [Example PR review](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/170)
+
+#### Review/mentoring contributions
+- Integration: Managed team repo, handled releases.
+- Reviewed a bulk of the pull requests (45+) to maintain code quality and initiate discussions where applicable.
+ - [Example of a non trivial PR review](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/87)
+ - [Another example](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/152)
+
+#### Contributions beyond the project team
+- Reported an above average number of bugs in the [PE-D](https://github.com/jacobkwan/ped/issues) (12)
diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md
deleted file mode 100644
index 773a07794e2..00000000000
--- a/docs/team/johndoe.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-layout: page
-title: John Doe's Project Portfolio Page
----
-
-### Project: AddressBook Level 3
-
-AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
-
-Given below are my contributions to the project.
-
-* **New Feature**: Added the ability to undo/redo previous commands.
- * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command.
- * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them.
- * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands.
- * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}*
-
-* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys.
-
-* **Code contributed**: [RepoSense link]()
-
-* **Project management**:
- * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub
-
-* **Enhancements to existing features**:
- * Updated the GUI color scheme (Pull requests [\#33](), [\#34]())
- * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]())
-
-* **Documentation**:
- * User Guide:
- * Added documentation for the features `delete` and `find` [\#72]()
- * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]()
- * Developer Guide:
- * Added implementation details of the `delete` feature.
-
-* **Community**:
- * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]()
- * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]())
- * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]())
- * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]())
-
-* **Tools**:
- * Integrated a third party library (Natty) to the project ([\#42]())
- * Integrated a new Github plugin (CircleCI) to the team repo
-
-* _{you can add/remove categories in the list above}_
diff --git a/docs/team/rylzxc.md b/docs/team/rylzxc.md
new file mode 100644
index 00000000000..1d6d162e917
--- /dev/null
+++ b/docs/team/rylzxc.md
@@ -0,0 +1,62 @@
+---
+layout: page
+title: Daryl Chua's Project Portfolio Page
+---
+
+## Project: WorkBook
+
+### Overview
+
+WorkBook (WB) is a desktop app for CS/tech students who are applying for internships to manage their internship applications, optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, WB can get your internship management tasks done faster than traditional GUI apps.
+
+### Summary of contributions
+
+#### Role in team
+
+Team lead: Overall in charge of the project, setting direction, keeping to deadlines and making important design decisions for the project.
+
+#### Code contributed
+This displays my code contributions for the project: [RepoSense link](https://nus-cs2103-ay2223s1.github.io/tp-dashboard/?search=rylzxc&breakdown=true)
+
+#### Enhancements implemented
+- New Feature: Adding [Date and Time field](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/65) for each internship application
+- New Feature: Adding [Stage field](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/58) to track internship application progress
+
+#### Contributions to User Guide
+- Overall tone, language and structure coordination
+- Introduce [numbering to table of contents](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/151)
+- Contribute to documenting:
+ - ['Introducing WorkBook' & 'Getting Started'](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/153)
+ - ['Parameter-specific behaviour' & 'Behaviour of sorted internship applications'](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/145)
+ - ['Add' & 'Edit' commands](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/165)
+ - ['Managing your data' & 'Frequently Asked Questions'](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/145)
+
+#### Contributions to Developer Guide
+- [`Add` command feature description, design considerations and class diagram](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/162)
+- [Update user stories](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/76)
+- [Use-case documentation](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/32/files) contributions to:
+ - Add an internship application
+ - Delete an internship application
+ - Edit an internship application
+ - Clear list of internship applications
+ - Display help message
+ - Exit application
+
+#### Contributions to team-based tasks
+
+* Set-up team repo
+* Maintain issue tracker & manage milestones
+* Release management
+* Liaise with professor and tutor to clarify tasks requirements
+
+#### Review/mentoring contributions
+
+* Jacob and I vet PRs, giving as much constructive feedback as possible before merging into the team repo
+
+#### Contributions beyond the project team
+
+* Aided in the [CATcher forums on Markdown styling](https://github.com/CATcher-org/CATcher/issues/1023)
+* Aided in solving [JUnit with Gradle](https://github.com/nus-cs2103-AY2223S1/forum/issues/79) issue in IntelliJ configuration error for iP
+* Aided in [answering quiz related question](https://github.com/nus-cs2103-AY2223S1/forum/issues/6)
+* Aided in [answering iP related issues](https://github.com/nus-cs2103-AY2223S1/forum/issues/82)
+* Aided in [OOP suggestion](https://github.com/nus-cs2103-AY2223S1/forum/issues/180)
diff --git a/docs/team/tienyu2000.md b/docs/team/tienyu2000.md
new file mode 100644
index 00000000000..882858322c2
--- /dev/null
+++ b/docs/team/tienyu2000.md
@@ -0,0 +1,147 @@
+---
+layout: page
+title: Tien's Project Portfolio Page
+---
+
+## Project: Workbook
+
+### Overview
+
+WorkBook is an internship application tracker that helps Computing students prepare sufficiently
+for their upcoming interviews to secure that internship. We also ensure that you never miss an
+interview or an application deadline ever again!
+Workbook is optimized for fast typists and utilizes a Command Line Interface (CLI) style while
+still having the benefits of a Graphical User Interface (GUI).
+
+### Summary of Contributions
+
+#### Code contributed
+Code contributions for the project: [RepoSense Link](https://nus-cs2103-ay2223s1.github.io/tp-dashboard/?search=tienyu2000&breakdown=true&sort=groupTitle&sortWithin=title&since=2022-09-16&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+#### Enhancements implemented
+
+- Major enhancement: added the ability to `undo` previous undoable command
+ - What it does: allows the user to undo previous undoable commands one at a time.
+ - Justification: This feature significantly improves the product by providing the user with a convenient way to rectify mistakes in commands.
+ - Highlights: This enhancement affected existing commands and was challenging to implement as it required changes to existing commands.
+
+- Major enhancement: added the ability to `redo` previous `undo` command
+ - What it does: allows the user to redo previous undo commands one at a time.
+ - Justification: This feature significantly improves the product by providing the user with a convenient way to rectify mistakes in undo commands.
+
+- Minor enhancement: added a delete command
+ - What it does: allow the user to delete an existing internship application
+ - Justification: This feature allows the user to remove an existing internship application from the WorkBook.
+
+
+#### Contributions to User Guide
+Added the implementation of the following commands to the User Guide:
+- `undo` : [Undoing a command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/154)
+- `redo`: [Redoing a command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/154)
+
+#### Contributions to Developer Guide
+- Outlined the design of the application
+- `Undo` and `Redo` command [feature implementation, design considerations,
+sequence diagrams, state diagrams and activity diagrams](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/98)
+- Use-case documentation contributions to UC06 - [Redo a command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/79)
+- User-stories documentation contributions to:
+ - As a student who constantly changes my mind, I want to [redo an undone command](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/79) so that I can revert
+ back the changes I had originally made.
+
+
+
+#### Contributions to team-based tasks
+- Updated [UML diagrams](https://github.com/AY2223S1-CS2103T-T10-3/tp/pull/98) in Developer's Guide
+
+#### Contributions beyond the project team
+[PE-D bugs reported in other team's products](https://github.com/tienyu2000/ped/issues)
+
+
+
+#### Contributions to User Guide (Extracts)
+
+1. Feature description
+
+ #### Undoing your previous command
+ What if you accidentally made a mistake and performed a wrong undoable command?
+Workbook can help you to undo your changes after performing an
+undesirable undoable command and restore itself to the
+previous version!
+
+ WorkBook keeps track of all your previous undoable commands and its current version, allowing you to `undo` as many times
+to restore any desired state of your WorkBook.
+
+ Format: `undo`
+ * Undo the previous undoable command.
+ * You can perform the `undo` command as many times as the number of tracked Workbook versions
+ i.e. stacking 2 undo commands sequentially will revert the WorkBook back 2
+ versions ago, assuming you performed at least 2 undoable commands previously!
+ * When you perform an undoable command, it will be stacked on top of the
+ previous undoable command in the stack. The `undo` command will undo the first undoable command at the
+ top of the stack.
+ * If you have not executed an undoable command previously, the WorkBook will remain in its current version
+ and return an error message: "No previous changes to undo!".
+
+
+2. Screenshot images
+
+
+ ![AfterUndo1](../images/AfterUndo1.png)
+
+
+
+#### Contributions to Developer Guide (Extracts)
+
+1. Undo/Redo Feature
+
+ The undo feature allows for users to revert back to their previous undone state in the Workbook.
+The redo feature complements the undo feature by allowing users to restore to its previous changed state following an undo command.
+
+2. Implementation
+
+ The undo/redo mechanism is facilitated by `VersionedWorkBook`. It extends `WorkBook` with an undo/redo history, stored internally as an `workBookStateList` and `currentStatePointer`. Additionally, it implements the following operations:
+
+ * `VersionedWorkBook#commit()` — Saves the current work book state in its history.
+ * `VersionedWorkBook#undo()` — Restores the previous work book state from its history.
+ * `VersionedWorkBook#redo()` — Restores a previously undone work book state from its history.
+
+ These operations are exposed in the `Model` interface as `Model#commitWorkBook()`, `Model#undoWorkBook()` and `Model#redoWorkBook()` 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 `VersionedWorkBook` will be initialized with the initial work book state, and the `currentStatePointer` pointing to that single work book state.
+
+ Step 2. The user executes `delete 5` command to delete the 5th internship in the work book. The `delete` command calls `Model#commitWorkBook()`, causing the modified state of the work book after the `delete 5` command executes to be saved in the `workBookStateList`, and the `currentStatePointer` is shifted to the newly inserted work book state.
+
+ Step 3. The user executes `add c/COMPANY …` to add a new internship. The `add` command also calls `Model#commitWorkBook()`, causing another modified work book state to be saved into the `workBookStateList`.
+
+ Step 4. The user now decides that adding the internship was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoWorkBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous work book state, and restores the work book to that state.
+
+ Step 5. The user now decides that undoing the added internship was a mistake, and decides to redo that action by executing the `redo` command. The `redo` command will call `Model#redoWorkBook()`, which will shift the `currentStatePointer` once to the right, pointing it to the previous undone work book state, and restores the work book to that state.
+
+ Step 6. The user then decides to execute the command `list`. Commands that do not modify the work book, such as `list`, will usually not call `Model#commitWorkBook()`, `Model#undoWorkBook()` or `Model#redoWorkBook()`. Thus, the `workBookStateList` remains unchanged.
+
+ Step 7. The user executes `clear`, which calls `Model#commitWorkBook()`. Since the `currentStatePointer` is not pointing at the end of the `workBookStateList`, all work book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add c/COMPANY …` command. This is the behavior that most modern desktop applications follow.
+
+ Design considerations:
+
+ **Aspect: How undo & redo executes:**
+
+ * **Alternative 1 (current choice):** Saves the entire work 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 internship being deleted).
+ * Cons: We must ensure that the implementation of each individual command are correct.
+
+
+3. UML diagrams
+
+![UndoRedoState6](../images/UndoRedoState6.png)
+
+
+![UndoSequenceDiagram](../images/UndoSequenceDiagram.png)
+
+
diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java
deleted file mode 100644
index 1deb3a1e469..00000000000
--- a/src/main/java/seedu/address/commons/core/Messages.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package seedu.address.commons.core;
-
-/**
- * Container for user visible messages.
- */
-public class Messages {
-
- public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
- 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!";
-
-}
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java
deleted file mode 100644
index 92cd8fa605a..00000000000
--- a/src/main/java/seedu/address/logic/Logic.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package seedu.address.logic;
-
-import java.nio.file.Path;
-
-import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * API of the Logic component
- */
-public interface Logic {
- /**
- * Executes the command and returns the result.
- * @param commandText The command as entered by the user.
- * @return the result of the command execution.
- * @throws CommandException If an error occurs during command execution.
- * @throws ParseException If an error occurs during parsing.
- */
- CommandResult execute(String commandText) throws CommandException, ParseException;
-
- /**
- * Returns the AddressBook.
- *
- * @see seedu.address.model.Model#getAddressBook()
- */
- ReadOnlyAddressBook getAddressBook();
-
- /** Returns an unmodifiable view of the filtered list of persons */
- ObservableList getFilteredPersonList();
-
- /**
- * Returns the user prefs' address book file path.
- */
- Path getAddressBookFilePath();
-
- /**
- * Returns the user prefs' GUI settings.
- */
- GuiSettings getGuiSettings();
-
- /**
- * Set the user prefs' GUI settings.
- */
- void setGuiSettings(GuiSettings guiSettings);
-}
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
deleted file mode 100644
index 71656d7c5c8..00000000000
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Person;
-
-/**
- * Adds a person to the address book.
- */
-public class AddCommand extends Command {
-
- public static final String COMMAND_WORD = "add";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. "
- + "Parameters: "
- + PREFIX_NAME + "NAME "
- + PREFIX_PHONE + "PHONE "
- + PREFIX_EMAIL + "EMAIL "
- + PREFIX_ADDRESS + "ADDRESS "
- + "[" + PREFIX_TAG + "TAG]...\n"
- + "Example: " + COMMAND_WORD + " "
- + PREFIX_NAME + "John Doe "
- + PREFIX_PHONE + "98765432 "
- + PREFIX_EMAIL + "johnd@example.com "
- + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
- + PREFIX_TAG + "friends "
- + PREFIX_TAG + "owesMoney";
-
- public static final String MESSAGE_SUCCESS = "New person added: %1$s";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book";
-
- private final Person toAdd;
-
- /**
- * Creates an AddCommand to add the specified {@code Person}
- */
- public AddCommand(Person person) {
- requireNonNull(person);
- toAdd = person;
- }
-
- @Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(model);
-
- if (model.hasPerson(toAdd)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
-
- model.addPerson(toAdd);
- return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof AddCommand // instanceof handles nulls
- && toAdd.equals(((AddCommand) other).toAdd));
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java
deleted file mode 100644
index 9c86b1fa6e4..00000000000
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-
-/**
- * Clears the address book.
- */
-public class ClearCommand extends Command {
-
- public static final String COMMAND_WORD = "clear";
- public static final String MESSAGE_SUCCESS = "Address book has been cleared!";
-
-
- @Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.setAddressBook(new AddressBook());
- return new CommandResult(MESSAGE_SUCCESS);
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
deleted file mode 100644
index 02fd256acba..00000000000
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.List;
-
-import seedu.address.commons.core.Messages;
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Person;
-
-/**
- * Deletes a person identified using it's displayed index from the address book.
- */
-public class DeleteCommand extends Command {
-
- public static final String COMMAND_WORD = "delete";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD
- + ": Deletes the person identified by the index number used in the displayed person list.\n"
- + "Parameters: INDEX (must be a positive integer)\n"
- + "Example: " + COMMAND_WORD + " 1";
-
- public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
-
- private final Index targetIndex;
-
- public DeleteCommand(Index targetIndex) {
- this.targetIndex = targetIndex;
- }
-
- @Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
-
- if (targetIndex.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
- }
-
- Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
- model.deletePerson(personToDelete);
- return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof DeleteCommand // instanceof handles nulls
- && targetIndex.equals(((DeleteCommand) other).targetIndex)); // state check
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
deleted file mode 100644
index 7e36114902f..00000000000
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ /dev/null
@@ -1,226 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-
-import java.util.Collections;
-import java.util.HashSet;
-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.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Edits the details of an existing person in the address book.
- */
-public class EditCommand extends Command {
-
- public static final String COMMAND_WORD = "edit";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified "
- + "by the index number used in the displayed person list. "
- + "Existing values will be overwritten by the input values.\n"
- + "Parameters: INDEX (must be a positive integer) "
- + "[" + PREFIX_NAME + "NAME] "
- + "[" + PREFIX_PHONE + "PHONE] "
- + "[" + PREFIX_EMAIL + "EMAIL] "
- + "[" + PREFIX_ADDRESS + "ADDRESS] "
- + "[" + PREFIX_TAG + "TAG]...\n"
- + "Example: " + COMMAND_WORD + " 1 "
- + PREFIX_PHONE + "91234567 "
- + PREFIX_EMAIL + "johndoe@example.com";
-
- public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s";
- public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book.";
-
- private final Index index;
- private final EditPersonDescriptor editPersonDescriptor;
-
- /**
- * @param index of the person in the filtered person list to edit
- * @param editPersonDescriptor details to edit the person with
- */
- public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
- requireNonNull(index);
- requireNonNull(editPersonDescriptor);
-
- this.index = index;
- this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor);
- }
-
- @Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(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, editPersonDescriptor);
-
- if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
-
- model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson));
- }
-
- /**
- * Creates and returns a {@code Person} with the details of {@code personToEdit}
- * edited with {@code editPersonDescriptor}.
- */
- private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
- assert personToEdit != null;
-
- Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName());
- Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone());
- Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail());
- Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
- Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
-
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
- }
-
- @Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof EditCommand)) {
- return false;
- }
-
- // state check
- EditCommand e = (EditCommand) other;
- return index.equals(e.index)
- && editPersonDescriptor.equals(e.editPersonDescriptor);
- }
-
- /**
- * Stores the details to edit the person with. Each non-empty field value will replace the
- * corresponding field value of the person.
- */
- public static class EditPersonDescriptor {
- private Name name;
- private Phone phone;
- private Email email;
- private Address address;
- private Set tags;
-
- public EditPersonDescriptor() {}
-
- /**
- * Copy constructor.
- * A defensive copy of {@code tags} is used internally.
- */
- public EditPersonDescriptor(EditPersonDescriptor toCopy) {
- setName(toCopy.name);
- setPhone(toCopy.phone);
- setEmail(toCopy.email);
- setAddress(toCopy.address);
- setTags(toCopy.tags);
- }
-
- /**
- * Returns true if at least one field is edited.
- */
- public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
- }
-
- public void setName(Name name) {
- this.name = name;
- }
-
- public Optional getName() {
- return Optional.ofNullable(name);
- }
-
- public void setPhone(Phone phone) {
- this.phone = phone;
- }
-
- public Optional getPhone() {
- return Optional.ofNullable(phone);
- }
-
- public void setEmail(Email email) {
- this.email = email;
- }
-
- public Optional getEmail() {
- return Optional.ofNullable(email);
- }
-
- public void setAddress(Address address) {
- this.address = address;
- }
-
- public Optional getAddress() {
- return Optional.ofNullable(address);
- }
-
- /**
- * Sets {@code tags} to this object's {@code tags}.
- * A defensive copy of {@code tags} is used internally.
- */
- public void setTags(Set tags) {
- this.tags = (tags != null) ? new HashSet<>(tags) : null;
- }
-
- /**
- * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- * Returns {@code Optional#empty()} if {@code tags} is null.
- */
- public Optional> getTags() {
- return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
- }
-
- @Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof EditPersonDescriptor)) {
- return false;
- }
-
- // state check
- EditPersonDescriptor e = (EditPersonDescriptor) other;
-
- return getName().equals(e.getName())
- && getPhone().equals(e.getPhone())
- && getEmail().equals(e.getEmail())
- && getAddress().equals(e.getAddress())
- && getTags().equals(e.getTags());
- }
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
deleted file mode 100644
index d6b19b0a0de..00000000000
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-
-import seedu.address.commons.core.Messages;
-import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-
-/**
- * Finds and lists all persons in address book whose name contains any of the argument keywords.
- * Keyword matching is case insensitive.
- */
-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";
-
- private final NameContainsKeywordsPredicate predicate;
-
- public FindCommand(NameContainsKeywordsPredicate predicate) {
- this.predicate = predicate;
- }
-
- @Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.updateFilteredPersonList(predicate);
- return new CommandResult(
- String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof FindCommand // instanceof handles nulls
- && predicate.equals(((FindCommand) other).predicate)); // state check
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
deleted file mode 100644
index 84be6ad2596..00000000000
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-
-import seedu.address.model.Model;
-
-/**
- * Lists all persons in the address book to the user.
- */
-public class ListCommand extends Command {
-
- public static final String COMMAND_WORD = "list";
-
- public static final String MESSAGE_SUCCESS = "Listed all persons";
-
-
- @Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(MESSAGE_SUCCESS);
- }
-}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
deleted file mode 100644
index 3b8bfa035e8..00000000000
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-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.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Parses input arguments and creates a new AddCommand object
- */
-public class AddCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the AddCommand
- * and returns an AddCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public AddCommand parse(String args) throws ParseException {
- ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
-
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
- || !argMultimap.getPreamble().isEmpty()) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
- }
-
- Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
- 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 tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
-
- Person person = new Person(name, phone, email, address, tagList);
-
- return new AddCommand(person);
- }
-
- /**
- * 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/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java
deleted file mode 100644
index 75b1a9bf119..00000000000
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package seedu.address.logic.parser;
-
-/**
- * Contains Command Line Interface (CLI) syntax definitions common to multiple commands
- */
-public class CliSyntax {
-
- /* Prefix definitions */
- 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/");
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
deleted file mode 100644
index 845644b7dea..00000000000
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ /dev/null
@@ -1,82 +0,0 @@
-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_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Optional;
-import java.util.Set;
-
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.tag.Tag;
-
-/**
- * Parses input arguments and creates a new EditCommand object
- */
-public class EditCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the EditCommand
- * and returns an EditCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public EditCommand parse(String args) throws ParseException {
- requireNonNull(args);
- ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
-
- Index index;
-
- try {
- index = ParserUtil.parseIndex(argMultimap.getPreamble());
- } catch (ParseException pe) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
- }
-
- EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
- if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
- editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
- }
- if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
- editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
- }
- if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
- }
- if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
- editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
- }
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
-
- if (!editPersonDescriptor.isAnyFieldEdited()) {
- throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
- }
-
- return new EditCommand(index, editPersonDescriptor);
- }
-
- /**
- * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty.
- * If {@code tags} contain only one element which is an empty string, it will be parsed into a
- * {@code Set} containing zero tags.
- */
- private Optional> parseTagsForEdit(Collection tags) throws ParseException {
- assert tags != null;
-
- if (tags.isEmpty()) {
- return Optional.empty();
- }
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
deleted file mode 100644
index 4fb71f23103..00000000000
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-
-import java.util.Arrays;
-
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-
-/**
- * Parses input arguments and creates a new FindCommand object
- */
-public class FindCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the FindCommand
- * and returns a FindCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public FindCommand parse(String args) throws ParseException {
- String trimmedArgs = args.trim();
- if (trimmedArgs.isEmpty()) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
- }
-
- String[] nameKeywords = trimmedArgs.split("\\s+");
-
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
- }
-
-}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
deleted file mode 100644
index 1a943a0781a..00000000000
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package seedu.address.model;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.List;
-
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.UniquePersonList;
-
-/**
- * Wraps all data at the address-book level
- * Duplicates are not allowed (by .isSamePerson comparison)
- */
-public class AddressBook implements ReadOnlyAddressBook {
-
- private final UniquePersonList persons;
-
- /*
- * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
- * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
- *
- * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication
- * among constructors.
- */
- {
- persons = new UniquePersonList();
- }
-
- public AddressBook() {}
-
- /**
- * Creates an AddressBook using the Persons in the {@code toBeCopied}
- */
- public AddressBook(ReadOnlyAddressBook toBeCopied) {
- this();
- resetData(toBeCopied);
- }
-
- //// list overwrite operations
-
- /**
- * Replaces the contents of the person list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- this.persons.setPersons(persons);
- }
-
- /**
- * Resets the existing data of this {@code AddressBook} with {@code newData}.
- */
- public void resetData(ReadOnlyAddressBook newData) {
- requireNonNull(newData);
-
- setPersons(newData.getPersonList());
- }
-
- //// person-level operations
-
- /**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
- */
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return persons.contains(person);
- }
-
- /**
- * Adds a person to the address book.
- * The person must not already exist in the address book.
- */
- public void addPerson(Person p) {
- persons.add(p);
- }
-
- /**
- * Replaces the given person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireNonNull(editedPerson);
-
- persons.setPerson(target, editedPerson);
- }
-
- /**
- * Removes {@code key} from this {@code AddressBook}.
- * {@code key} must exist in the address book.
- */
- public void removePerson(Person key) {
- persons.remove(key);
- }
-
- //// util methods
-
- @Override
- public String toString() {
- return persons.asUnmodifiableObservableList().size() + " persons";
- // TODO: refine later
- }
-
- @Override
- public ObservableList getPersonList() {
- return persons.asUnmodifiableObservableList();
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof AddressBook // instanceof handles nulls
- && persons.equals(((AddressBook) other).persons));
- }
-
- @Override
- 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
deleted file mode 100644
index d54df471c1f..00000000000
--- a/src/main/java/seedu/address/model/Model.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package seedu.address.model;
-
-import java.nio.file.Path;
-import java.util.function.Predicate;
-
-import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.person.Person;
-
-/**
- * The API of the Model component.
- */
-public interface Model {
- /** {@code Predicate} that always evaluate to true */
- Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true;
-
- /**
- * Replaces user prefs data with the data in {@code userPrefs}.
- */
- void setUserPrefs(ReadOnlyUserPrefs userPrefs);
-
- /**
- * Returns the user prefs.
- */
- ReadOnlyUserPrefs getUserPrefs();
-
- /**
- * Returns the user prefs' GUI settings.
- */
- GuiSettings getGuiSettings();
-
- /**
- * Sets the user prefs' GUI settings.
- */
- void setGuiSettings(GuiSettings guiSettings);
-
- /**
- * Returns the user prefs' address book file path.
- */
- Path getAddressBookFilePath();
-
- /**
- * Sets the user prefs' address book file path.
- */
- void setAddressBookFilePath(Path addressBookFilePath);
-
- /**
- * Replaces address book data with the data in {@code addressBook}.
- */
- void setAddressBook(ReadOnlyAddressBook addressBook);
-
- /** Returns the AddressBook */
- ReadOnlyAddressBook getAddressBook();
-
- /**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
- */
- boolean hasPerson(Person person);
-
- /**
- * Deletes the given person.
- * The person must exist in the address book.
- */
- void deletePerson(Person target);
-
- /**
- * Adds the given person.
- * {@code person} must not already exist in the address book.
- */
- void addPerson(Person person);
-
- /**
- * Replaces the given person {@code target} with {@code editedPerson}.
- * {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
- */
- void setPerson(Person target, Person editedPerson);
-
- /** Returns an unmodifiable view of the filtered person list */
- ObservableList getFilteredPersonList();
-
- /**
- * Updates the filter of the filtered person list to filter by the given {@code predicate}.
- * @throws NullPointerException if {@code predicate} is null.
- */
- void updateFilteredPersonList(Predicate predicate);
-}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
deleted file mode 100644
index 86c1df298d7..00000000000
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package seedu.address.model;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.nio.file.Path;
-import java.util.function.Predicate;
-import java.util.logging.Logger;
-
-import javafx.collections.ObservableList;
-import javafx.collections.transformation.FilteredList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
-
-/**
- * Represents the in-memory model of the address book data.
- */
-public class ModelManager implements Model {
- private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
-
- private final AddressBook addressBook;
- private final UserPrefs userPrefs;
- private final FilteredList filteredPersons;
-
- /**
- * Initializes a ModelManager with the given addressBook and userPrefs.
- */
- public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) {
- requireAllNonNull(addressBook, userPrefs);
-
- logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);
-
- this.addressBook = new AddressBook(addressBook);
- this.userPrefs = new UserPrefs(userPrefs);
- filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
- }
-
- public ModelManager() {
- this(new AddressBook(), new UserPrefs());
- }
-
- //=========== UserPrefs ==================================================================================
-
- @Override
- public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
- requireNonNull(userPrefs);
- this.userPrefs.resetData(userPrefs);
- }
-
- @Override
- public ReadOnlyUserPrefs getUserPrefs() {
- return userPrefs;
- }
-
- @Override
- public GuiSettings getGuiSettings() {
- return userPrefs.getGuiSettings();
- }
-
- @Override
- public void setGuiSettings(GuiSettings guiSettings) {
- requireNonNull(guiSettings);
- userPrefs.setGuiSettings(guiSettings);
- }
-
- @Override
- public Path getAddressBookFilePath() {
- return userPrefs.getAddressBookFilePath();
- }
-
- @Override
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- userPrefs.setAddressBookFilePath(addressBookFilePath);
- }
-
- //=========== AddressBook ================================================================================
-
- @Override
- public void setAddressBook(ReadOnlyAddressBook addressBook) {
- this.addressBook.resetData(addressBook);
- }
-
- @Override
- public ReadOnlyAddressBook getAddressBook() {
- return addressBook;
- }
-
- @Override
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return addressBook.hasPerson(person);
- }
-
- @Override
- public void deletePerson(Person target) {
- addressBook.removePerson(target);
- }
-
- @Override
- public void addPerson(Person person) {
- addressBook.addPerson(person);
- updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- }
-
- @Override
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
-
- addressBook.setPerson(target, editedPerson);
- }
-
- //=========== Filtered Person List Accessors =============================================================
-
- /**
- * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of
- * {@code versionedAddressBook}
- */
- @Override
- public ObservableList getFilteredPersonList() {
- return filteredPersons;
- }
-
- @Override
- public void updateFilteredPersonList(Predicate predicate) {
- requireNonNull(predicate);
- filteredPersons.setPredicate(predicate);
- }
-
- @Override
- public boolean equals(Object obj) {
- // short circuit if same object
- if (obj == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(obj instanceof ModelManager)) {
- return false;
- }
-
- // state check
- ModelManager other = (ModelManager) obj;
- return addressBook.equals(other.addressBook)
- && userPrefs.equals(other.userPrefs)
- && filteredPersons.equals(other.filteredPersons);
- }
-
-}
diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
deleted file mode 100644
index 6ddc2cd9a29..00000000000
--- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package seedu.address.model;
-
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-
-/**
- * Unmodifiable view of an address book
- */
-public interface ReadOnlyAddressBook {
-
- /**
- * Returns an unmodifiable view of the persons list.
- * This list will not contain any duplicate persons.
- */
- ObservableList getPersonList();
-
-}
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java
deleted file mode 100644
index 60472ca22a0..00000000000
--- a/src/main/java/seedu/address/model/person/Address.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's address in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)}
- */
-public class Address {
-
- public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank";
-
- /*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
- */
- public static final String VALIDATION_REGEX = "[^\\s].*";
-
- public final String value;
-
- /**
- * Constructs an {@code Address}.
- *
- * @param address A valid address.
- */
- public Address(String address) {
- requireNonNull(address);
- checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS);
- value = address;
- }
-
- /**
- * Returns true if a given string is a valid email.
- */
- public static boolean isValidAddress(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public String toString() {
- return value;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Address // instanceof handles nulls
- && value.equals(((Address) other).value)); // state check
- }
-
- @Override
- public int hashCode() {
- return value.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/person/Name.java
deleted file mode 100644
index 79244d71cf7..00000000000
--- a/src/main/java/seedu/address/model/person/Name.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's name in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidName(String)}
- */
-public class Name {
-
- public static final String MESSAGE_CONSTRAINTS =
- "Names should only contain alphanumeric characters and spaces, and it should not be blank";
-
- /*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
- */
- public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
-
- public final String fullName;
-
- /**
- * Constructs a {@code Name}.
- *
- * @param name A valid name.
- */
- public Name(String name) {
- requireNonNull(name);
- checkArgument(isValidName(name), MESSAGE_CONSTRAINTS);
- fullName = name;
- }
-
- /**
- * Returns true if a given string is a valid name.
- */
- public static boolean isValidName(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
-
- @Override
- public String toString() {
- return fullName;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Name // instanceof handles nulls
- && fullName.equals(((Name) other).fullName)); // state check
- }
-
- @Override
- public int hashCode() {
- return fullName.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
deleted file mode 100644
index c9b5868427c..00000000000
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ /dev/null
@@ -1,31 +0,0 @@
-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 Name} matches any of the keywords given.
- */
-public class NameContainsKeywordsPredicate implements Predicate {
- private final List keywords;
-
- public NameContainsKeywordsPredicate(List keywords) {
- this.keywords = keywords;
- }
-
- @Override
- public boolean test(Person person) {
- return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof NameContainsKeywordsPredicate // instanceof handles nulls
- && keywords.equals(((NameContainsKeywordsPredicate) other).keywords)); // state check
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
deleted file mode 100644
index 8ff1d83fe89..00000000000
--- a/src/main/java/seedu/address/model/person/Person.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package seedu.address.model.person;
-
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
-import seedu.address.model.tag.Tag;
-
-/**
- * Represents a Person in the address book.
- * Guarantees: details are present and not null, field values are validated, immutable.
- */
-public class Person {
-
- // Identity fields
- private final Name name;
- private final Phone phone;
- private final Email email;
-
- // Data fields
- private final Address address;
- private final Set tags = new HashSet<>();
-
- /**
- * Every field must be present and not null.
- */
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
- requireAllNonNull(name, phone, email, address, tags);
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- this.tags.addAll(tags);
- }
-
- public Name getName() {
- return name;
- }
-
- public Phone getPhone() {
- return phone;
- }
-
- public Email getEmail() {
- return email;
- }
-
- public Address getAddress() {
- return address;
- }
-
- /**
- * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- */
- public Set getTags() {
- return Collections.unmodifiableSet(tags);
- }
-
- /**
- * Returns true if both persons have the same name.
- * This defines a weaker notion of equality between two persons.
- */
- public boolean isSamePerson(Person otherPerson) {
- if (otherPerson == this) {
- return true;
- }
-
- return otherPerson != null
- && otherPerson.getName().equals(getName());
- }
-
- /**
- * Returns true if both persons have the same identity and data fields.
- * This defines a stronger notion of equality between two persons.
- */
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- if (!(other instanceof Person)) {
- return false;
- }
-
- Person otherPerson = (Person) other;
- return otherPerson.getName().equals(getName())
- && otherPerson.getPhone().equals(getPhone())
- && otherPerson.getEmail().equals(getEmail())
- && otherPerson.getAddress().equals(getAddress())
- && otherPerson.getTags().equals(getTags());
- }
-
- @Override
- public int hashCode() {
- // use this method for custom fields hashing instead of implementing your own
- return Objects.hash(name, phone, email, address, tags);
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append(getName())
- .append("; Phone: ")
- .append(getPhone())
- .append("; Email: ")
- .append(getEmail())
- .append("; Address: ")
- .append(getAddress());
-
- Set tags = getTags();
- if (!tags.isEmpty()) {
- builder.append("; Tags: ");
- tags.forEach(builder::append);
- }
- return builder.toString();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/person/Phone.java
deleted file mode 100644
index 872c76b382f..00000000000
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's phone number in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)}
- */
-public class Phone {
-
-
- public static final String MESSAGE_CONSTRAINTS =
- "Phone numbers should only contain numbers, and it should be at least 3 digits long";
- public static final String VALIDATION_REGEX = "\\d{3,}";
- public final String value;
-
- /**
- * Constructs a {@code Phone}.
- *
- * @param phone A valid phone number.
- */
- public Phone(String phone) {
- requireNonNull(phone);
- checkArgument(isValidPhone(phone), MESSAGE_CONSTRAINTS);
- value = phone;
- }
-
- /**
- * Returns true if a given string is a valid phone number.
- */
- public static boolean isValidPhone(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public String toString() {
- return value;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Phone // instanceof handles nulls
- && value.equals(((Phone) other).value)); // state check
- }
-
- @Override
- public int hashCode() {
- return value.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java
deleted file mode 100644
index 0fee4fe57e6..00000000000
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Iterator;
-import java.util.List;
-
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.model.person.exceptions.PersonNotFoundException;
-
-/**
- * A list of persons that enforces uniqueness between its elements and does not allow nulls.
- * A person is considered unique by comparing using {@code Person#isSamePerson(Person)}. As such, adding and updating of
- * persons uses Person#isSamePerson(Person) for equality so as to ensure that the person being added or updated is
- * unique in terms of identity in the UniquePersonList. However, the removal of a person uses Person#equals(Object) so
- * as to ensure that the person with exactly the same fields will be removed.
- *
- * Supports a minimal set of list operations.
- *
- * @see Person#isSamePerson(Person)
- */
-public class UniquePersonList implements Iterable {
-
- private final ObservableList internalList = FXCollections.observableArrayList();
- private final ObservableList internalUnmodifiableList =
- FXCollections.unmodifiableObservableList(internalList);
-
- /**
- * Returns true if the list contains an equivalent person as the given argument.
- */
- public boolean contains(Person toCheck) {
- requireNonNull(toCheck);
- return internalList.stream().anyMatch(toCheck::isSamePerson);
- }
-
- /**
- * Adds a person to the list.
- * The person must not already exist in the list.
- */
- public void add(Person toAdd) {
- requireNonNull(toAdd);
- if (contains(toAdd)) {
- throw new DuplicatePersonException();
- }
- internalList.add(toAdd);
- }
-
- /**
- * Replaces the person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the list.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the list.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
-
- int index = internalList.indexOf(target);
- if (index == -1) {
- throw new PersonNotFoundException();
- }
-
- if (!target.isSamePerson(editedPerson) && contains(editedPerson)) {
- throw new DuplicatePersonException();
- }
-
- internalList.set(index, editedPerson);
- }
-
- /**
- * Removes the equivalent person from the list.
- * The person must exist in the list.
- */
- public void remove(Person toRemove) {
- requireNonNull(toRemove);
- if (!internalList.remove(toRemove)) {
- throw new PersonNotFoundException();
- }
- }
-
- public void setPersons(UniquePersonList replacement) {
- requireNonNull(replacement);
- internalList.setAll(replacement.internalList);
- }
-
- /**
- * Replaces the contents of this list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- requireAllNonNull(persons);
- if (!personsAreUnique(persons)) {
- throw new DuplicatePersonException();
- }
-
- internalList.setAll(persons);
- }
-
- /**
- * Returns the backing list as an unmodifiable {@code ObservableList}.
- */
- public ObservableList asUnmodifiableObservableList() {
- return internalUnmodifiableList;
- }
-
- @Override
- public Iterator iterator() {
- return internalList.iterator();
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof UniquePersonList // instanceof handles nulls
- && internalList.equals(((UniquePersonList) other).internalList));
- }
-
- @Override
- public int hashCode() {
- return internalList.hashCode();
- }
-
- /**
- * Returns true if {@code persons} contains only unique persons.
- */
- private boolean personsAreUnique(List persons) {
- for (int i = 0; i < persons.size() - 1; i++) {
- for (int j = i + 1; j < persons.size(); j++) {
- if (persons.get(i).isSamePerson(persons.get(j))) {
- return false;
- }
- }
- }
- return true;
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
deleted file mode 100644
index d7290f59442..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation will result in duplicate Persons (Persons are considered duplicates if they have the same
- * identity).
- */
-public class DuplicatePersonException extends RuntimeException {
- public DuplicatePersonException() {
- super("Operation would result in duplicate persons");
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
deleted file mode 100644
index fa764426ca7..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation is unable to find the specified person.
- */
-public class PersonNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
deleted file mode 100644
index 1806da4facf..00000000000
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.model.util;
-
-import java.util.Arrays;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Contains utility methods for populating {@code AddressBook} with sample data.
- */
-public class SampleDataUtil {
- 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 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 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 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 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 Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"),
- new Address("Blk 45 Aljunied Street 85, #11-31"),
- getTagSet("colleagues"))
- };
- }
-
- public static ReadOnlyAddressBook getSampleAddressBook() {
- AddressBook sampleAb = new AddressBook();
- for (Person samplePerson : getSamplePersons()) {
- sampleAb.addPerson(samplePerson);
- }
- return sampleAb;
- }
-
- /**
- * Returns a tag set containing the list of strings given.
- */
- public static Set getTagSet(String... strings) {
- return Arrays.stream(strings)
- .map(Tag::new)
- .collect(Collectors.toSet());
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/seedu/address/storage/AddressBookStorage.java
deleted file mode 100644
index 4599182b3f9..00000000000
--- a/src/main/java/seedu/address/storage/AddressBookStorage.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-
-/**
- * Represents a storage for {@link seedu.address.model.AddressBook}.
- */
-public interface AddressBookStorage {
-
- /**
- * Returns the file path of the data file.
- */
- Path getAddressBookFilePath();
-
- /**
- * Returns AddressBook data as a {@link ReadOnlyAddressBook}.
- * Returns {@code Optional.empty()} if storage file is not found.
- * @throws DataConversionException if the data in storage is not in the expected format.
- * @throws IOException if there was any problem when reading from the storage.
- */
- Optional readAddressBook() throws DataConversionException, IOException;
-
- /**
- * @see #getAddressBookFilePath()
- */
- Optional readAddressBook(Path filePath) throws DataConversionException, IOException;
-
- /**
- * Saves the given {@link ReadOnlyAddressBook} to the storage.
- * @param addressBook cannot be null.
- * @throws IOException if there was any problem writing to the file.
- */
- void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
-
- /**
- * @see #saveAddressBook(ReadOnlyAddressBook)
- */
- void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException;
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
deleted file mode 100644
index a6321cec2ea..00000000000
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Jackson-friendly version of {@link Person}.
- */
-class JsonAdaptedPerson {
-
- public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!";
-
- private final String name;
- private final String phone;
- private final String email;
- private final String address;
- private final List tagged = new ArrayList<>();
-
- /**
- * Constructs a {@code JsonAdaptedPerson} with the given person details.
- */
- @JsonCreator
- public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
- @JsonProperty("email") String email, @JsonProperty("address") String address,
- @JsonProperty("tagged") List tagged) {
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- if (tagged != null) {
- this.tagged.addAll(tagged);
- }
- }
-
- /**
- * Converts a given {@code Person} into this class for Jackson use.
- */
- public JsonAdaptedPerson(Person source) {
- name = source.getName().fullName;
- phone = source.getPhone().value;
- email = source.getEmail().value;
- address = source.getAddress().value;
- tagged.addAll(source.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList()));
- }
-
- /**
- * Converts this Jackson-friendly adapted person object into the model's {@code Person} object.
- *
- * @throws IllegalValueException if there were any data constraints violated in the adapted person.
- */
- public Person toModelType() throws IllegalValueException {
- final List personTags = new ArrayList<>();
- for (JsonAdaptedTag tag : tagged) {
- personTags.add(tag.toModelType());
- }
-
- if (name == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
- }
- if (!Name.isValidName(name)) {
- throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
- }
- final Name modelName = new Name(name);
-
- if (phone == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()));
- }
- if (!Phone.isValidPhone(phone)) {
- throw new IllegalValueException(Phone.MESSAGE_CONSTRAINTS);
- }
- final Phone modelPhone = new Phone(phone);
-
- if (email == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()));
- }
- if (!Email.isValidEmail(email)) {
- throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS);
- }
- final Email modelEmail = new Email(email);
-
- if (address == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()));
- }
- if (!Address.isValidAddress(address)) {
- throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS);
- }
- final Address modelAddress = new Address(address);
-
- final Set modelTags = new HashSet<>(personTags);
- return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
deleted file mode 100644
index dfab9daaa0d..00000000000
--- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package seedu.address.storage;
-
-import static java.util.Objects.requireNonNull;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-import java.util.logging.Logger;
-
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.commons.util.FileUtil;
-import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.ReadOnlyAddressBook;
-
-/**
- * A class to access AddressBook data stored as a json file on the hard disk.
- */
-public class JsonAddressBookStorage implements AddressBookStorage {
-
- private static final Logger logger = LogsCenter.getLogger(JsonAddressBookStorage.class);
-
- private Path filePath;
-
- public JsonAddressBookStorage(Path filePath) {
- this.filePath = filePath;
- }
-
- public Path getAddressBookFilePath() {
- return filePath;
- }
-
- @Override
- public Optional readAddressBook() throws DataConversionException {
- return readAddressBook(filePath);
- }
-
- /**
- * Similar to {@link #readAddressBook()}.
- *
- * @param filePath location of the data. Cannot be null.
- * @throws DataConversionException if the file is not in the correct format.
- */
- public Optional readAddressBook(Path filePath) throws DataConversionException {
- requireNonNull(filePath);
-
- Optional jsonAddressBook = JsonUtil.readJsonFile(
- filePath, JsonSerializableAddressBook.class);
- if (!jsonAddressBook.isPresent()) {
- return Optional.empty();
- }
-
- try {
- return Optional.of(jsonAddressBook.get().toModelType());
- } catch (IllegalValueException ive) {
- logger.info("Illegal values found in " + filePath + ": " + ive.getMessage());
- throw new DataConversionException(ive);
- }
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, filePath);
- }
-
- /**
- * Similar to {@link #saveAddressBook(ReadOnlyAddressBook)}.
- *
- * @param filePath location of the data. Cannot be null.
- */
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
- requireNonNull(addressBook);
- requireNonNull(filePath);
-
- FileUtil.createIfMissing(filePath);
- JsonUtil.saveJsonFile(new JsonSerializableAddressBook(addressBook), filePath);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
deleted file mode 100644
index 5efd834091d..00000000000
--- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonRootName;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * An Immutable AddressBook that is serializable to JSON format.
- */
-@JsonRootName(value = "addressbook")
-class JsonSerializableAddressBook {
-
- public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
-
- private final List persons = new ArrayList<>();
-
- /**
- * Constructs a {@code JsonSerializableAddressBook} with the given persons.
- */
- @JsonCreator
- public JsonSerializableAddressBook(@JsonProperty("persons") List persons) {
- this.persons.addAll(persons);
- }
-
- /**
- * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use.
- *
- * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}.
- */
- public JsonSerializableAddressBook(ReadOnlyAddressBook source) {
- persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList()));
- }
-
- /**
- * Converts this address book into the model's {@code AddressBook} object.
- *
- * @throws IllegalValueException if there were any data constraints violated.
- */
- public AddressBook toModelType() throws IllegalValueException {
- AddressBook addressBook = new AddressBook();
- for (JsonAdaptedPerson jsonAdaptedPerson : persons) {
- Person person = jsonAdaptedPerson.toModelType();
- if (addressBook.hasPerson(person)) {
- throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON);
- }
- addressBook.addPerson(person);
- }
- return addressBook;
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java
deleted file mode 100644
index beda8bd9f11..00000000000
--- a/src/main/java/seedu/address/storage/Storage.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-
-/**
- * API of the Storage component
- */
-public interface Storage extends AddressBookStorage, UserPrefsStorage {
-
- @Override
- Optional readUserPrefs() throws DataConversionException, IOException;
-
- @Override
- void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException;
-
- @Override
- Path getAddressBookFilePath();
-
- @Override
- Optional readAddressBook() throws DataConversionException, IOException;
-
- @Override
- void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
-
-}
diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java
deleted file mode 100644
index 6cfa0162164..00000000000
--- a/src/main/java/seedu/address/storage/StorageManager.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-import java.util.logging.Logger;
-
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-
-/**
- * Manages storage of AddressBook data in local storage.
- */
-public class StorageManager implements Storage {
-
- private static final Logger logger = LogsCenter.getLogger(StorageManager.class);
- private AddressBookStorage addressBookStorage;
- private UserPrefsStorage userPrefsStorage;
-
- /**
- * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}.
- */
- public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) {
- this.addressBookStorage = addressBookStorage;
- this.userPrefsStorage = userPrefsStorage;
- }
-
- // ================ UserPrefs methods ==============================
-
- @Override
- public Path getUserPrefsFilePath() {
- return userPrefsStorage.getUserPrefsFilePath();
- }
-
- @Override
- public Optional readUserPrefs() throws DataConversionException, IOException {
- return userPrefsStorage.readUserPrefs();
- }
-
- @Override
- public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException {
- userPrefsStorage.saveUserPrefs(userPrefs);
- }
-
-
- // ================ AddressBook methods ==============================
-
- @Override
- public Path getAddressBookFilePath() {
- return addressBookStorage.getAddressBookFilePath();
- }
-
- @Override
- public Optional readAddressBook() throws DataConversionException, IOException {
- return readAddressBook(addressBookStorage.getAddressBookFilePath());
- }
-
- @Override
- public Optional readAddressBook(Path filePath) throws DataConversionException, IOException {
- logger.fine("Attempting to read data from file: " + filePath);
- return addressBookStorage.readAddressBook(filePath);
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, addressBookStorage.getAddressBookFilePath());
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
- logger.fine("Attempting to write to data file: " + filePath);
- addressBookStorage.saveAddressBook(addressBook, filePath);
- }
-
-}
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
deleted file mode 100644
index 7fc927bc5d9..00000000000
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package seedu.address.ui;
-
-import java.util.Comparator;
-
-import javafx.fxml.FXML;
-import javafx.scene.control.Label;
-import javafx.scene.layout.FlowPane;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Region;
-import seedu.address.model.person.Person;
-
-/**
- * An UI component that displays information of a {@code Person}.
- */
-public class PersonCard extends UiPart {
-
- private static final String FXML = "PersonListCard.fxml";
-
- /**
- * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
- * As a consequence, UI elements' variable names cannot be set to such keywords
- * or an exception will be thrown by JavaFX during runtime.
- *
- * @see The issue on AddressBook level 4
- */
-
- public final Person person;
-
- @FXML
- private HBox cardPane;
- @FXML
- private Label name;
- @FXML
- private Label id;
- @FXML
- private Label phone;
- @FXML
- private Label address;
- @FXML
- private Label email;
- @FXML
- private FlowPane tags;
-
- /**
- * Creates a {@code PersonCode} with the given {@code Person} and index to display.
- */
- public PersonCard(Person person, int displayedIndex) {
- super(FXML);
- this.person = person;
- id.setText(displayedIndex + ". ");
- name.setText(person.getName().fullName);
- phone.setText(person.getPhone().value);
- address.setText(person.getAddress().value);
- email.setText(person.getEmail().value);
- person.getTags().stream()
- .sorted(Comparator.comparing(tag -> tag.tagName))
- .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
- }
-
- @Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof PersonCard)) {
- return false;
- }
-
- // state check
- PersonCard card = (PersonCard) other;
- return id.getText().equals(card.id.getText())
- && person.equals(card.person);
- }
-}
diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java
deleted file mode 100644
index f4c501a897b..00000000000
--- a/src/main/java/seedu/address/ui/PersonListPanel.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package seedu.address.ui;
-
-import java.util.logging.Logger;
-
-import javafx.collections.ObservableList;
-import javafx.fxml.FXML;
-import javafx.scene.control.ListCell;
-import javafx.scene.control.ListView;
-import javafx.scene.layout.Region;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
-
-/**
- * Panel containing the list of persons.
- */
-public class PersonListPanel extends UiPart {
- private static final String FXML = "PersonListPanel.fxml";
- private final Logger logger = LogsCenter.getLogger(PersonListPanel.class);
-
- @FXML
- private ListView personListView;
-
- /**
- * Creates a {@code PersonListPanel} with the given {@code ObservableList}.
- */
- public PersonListPanel(ObservableList personList) {
- super(FXML);
- personListView.setItems(personList);
- personListView.setCellFactory(listView -> new PersonListViewCell());
- }
-
- /**
- * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}.
- */
- class PersonListViewCell extends ListCell {
- @Override
- protected void updateItem(Person person, boolean empty) {
- super.updateItem(person, empty);
-
- if (empty || person == null) {
- setGraphic(null);
- setText(null);
- } else {
- setGraphic(new PersonCard(person, getIndex() + 1).getRoot());
- }
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/AppParameters.java b/src/main/java/seedu/workbook/AppParameters.java
similarity index 93%
rename from src/main/java/seedu/address/AppParameters.java
rename to src/main/java/seedu/workbook/AppParameters.java
index ab552c398f3..f90f76a8d70 100644
--- a/src/main/java/seedu/address/AppParameters.java
+++ b/src/main/java/seedu/workbook/AppParameters.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.workbook;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -7,8 +7,8 @@
import java.util.logging.Logger;
import javafx.application.Application;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.util.FileUtil;
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.commons.util.FileUtil;
/**
* Represents the parsed command-line parameters given to the application.
diff --git a/src/main/java/seedu/address/Main.java b/src/main/java/seedu/workbook/Main.java
similarity index 97%
rename from src/main/java/seedu/address/Main.java
rename to src/main/java/seedu/workbook/Main.java
index 052a5068631..82b6d177581 100644
--- a/src/main/java/seedu/address/Main.java
+++ b/src/main/java/seedu/workbook/Main.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.workbook;
import javafx.application.Application;
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/workbook/MainApp.java
similarity index 67%
rename from src/main/java/seedu/address/MainApp.java
rename to src/main/java/seedu/workbook/MainApp.java
index 4133aaa0151..4d3ee4327ee 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/workbook/MainApp.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.workbook;
import java.io.IOException;
import java.nio.file.Path;
@@ -7,36 +7,36 @@
import javafx.application.Application;
import javafx.stage.Stage;
-import seedu.address.commons.core.Config;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.core.Version;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.commons.util.ConfigUtil;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.logic.Logic;
-import seedu.address.logic.LogicManager;
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.util.SampleDataUtil;
-import seedu.address.storage.AddressBookStorage;
-import seedu.address.storage.JsonAddressBookStorage;
-import seedu.address.storage.JsonUserPrefsStorage;
-import seedu.address.storage.Storage;
-import seedu.address.storage.StorageManager;
-import seedu.address.storage.UserPrefsStorage;
-import seedu.address.ui.Ui;
-import seedu.address.ui.UiManager;
+import seedu.workbook.commons.core.Config;
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.commons.core.Version;
+import seedu.workbook.commons.exceptions.DataConversionException;
+import seedu.workbook.commons.util.ConfigUtil;
+import seedu.workbook.commons.util.StringUtil;
+import seedu.workbook.logic.Logic;
+import seedu.workbook.logic.LogicManager;
+import seedu.workbook.model.Model;
+import seedu.workbook.model.ModelManager;
+import seedu.workbook.model.ReadOnlyUserPrefs;
+import seedu.workbook.model.ReadOnlyWorkBook;
+import seedu.workbook.model.UserPrefs;
+import seedu.workbook.model.WorkBook;
+import seedu.workbook.model.util.SampleDataUtil;
+import seedu.workbook.storage.JsonUserPrefsStorage;
+import seedu.workbook.storage.JsonWorkBookStorage;
+import seedu.workbook.storage.Storage;
+import seedu.workbook.storage.StorageManager;
+import seedu.workbook.storage.UserPrefsStorage;
+import seedu.workbook.storage.WorkBookStorage;
+import seedu.workbook.ui.Ui;
+import seedu.workbook.ui.UiManager;
/**
* Runs the application.
*/
public class MainApp extends Application {
- public static final Version VERSION = new Version(0, 2, 0, true);
+ public static final Version VERSION = new Version(1, 4, 1, true);
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
@@ -48,7 +48,7 @@ public class MainApp extends Application {
@Override
public void init() throws Exception {
- logger.info("=============================[ Initializing AddressBook ]===========================");
+ logger.info("=============================[ Initializing WorkBook ]===========================");
super.init();
AppParameters appParameters = AppParameters.parse(getParameters());
@@ -56,8 +56,8 @@ public void init() throws Exception {
UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath());
UserPrefs userPrefs = initPrefs(userPrefsStorage);
- AddressBookStorage addressBookStorage = new JsonAddressBookStorage(userPrefs.getAddressBookFilePath());
- storage = new StorageManager(addressBookStorage, userPrefsStorage);
+ WorkBookStorage workBookStorage = new JsonWorkBookStorage(userPrefs.getWorkBookFilePath());
+ storage = new StorageManager(workBookStorage, userPrefsStorage);
initLogging(config);
@@ -69,25 +69,25 @@ public void init() throws Exception {
}
/**
- * Returns a {@code ModelManager} with the data from {@code storage}'s address book and {@code userPrefs}.
- * The data from the sample address book will be used instead if {@code storage}'s address book is not found,
- * or an empty address book will be used instead if errors occur when reading {@code storage}'s address book.
+ * Returns a {@code ModelManager} with the data from {@code storage}'s work book and {@code userPrefs}.
+ * The data from the sample work book will be used instead if {@code storage}'s work book is not found,
+ * or an empty work book will be used instead if errors occur when reading {@code storage}'s work book.
*/
private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
- Optional addressBookOptional;
- ReadOnlyAddressBook initialData;
+ Optional workBookOptional;
+ ReadOnlyWorkBook initialData;
try {
- addressBookOptional = storage.readAddressBook();
- if (!addressBookOptional.isPresent()) {
- logger.info("Data file not found. Will be starting with a sample AddressBook");
+ workBookOptional = storage.readWorkBook();
+ if (!workBookOptional.isPresent()) {
+ logger.info("Data file not found. Will be starting with a sample WorkBook");
}
- initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
+ initialData = workBookOptional.orElseGet(SampleDataUtil::getSampleWorkBook);
} catch (DataConversionException e) {
- logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook");
- initialData = new AddressBook();
+ logger.warning("Data file not in the correct format. Will be starting with an empty WorkBook");
+ initialData = new WorkBook();
} catch (IOException e) {
- logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook");
- initialData = new AddressBook();
+ logger.warning("Problem while reading from the file. Will be starting with an empty WorkBook");
+ initialData = new WorkBook();
}
return new ModelManager(initialData, userPrefs);
@@ -151,7 +151,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
+ "Using default user prefs");
initializedPrefs = new UserPrefs();
} catch (IOException e) {
- logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook");
+ logger.warning("Problem while reading from the file. Will be starting with an empty WorkBook");
initializedPrefs = new UserPrefs();
}
@@ -167,13 +167,13 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
@Override
public void start(Stage primaryStage) {
- logger.info("Starting AddressBook " + MainApp.VERSION);
+ logger.info("Starting WorkBook " + MainApp.VERSION);
ui.start(primaryStage);
}
@Override
public void stop() {
- logger.info("============================ [ Stopping Address Book ] =============================");
+ logger.info("============================ [ Stopping Work Book ] =============================");
try {
storage.saveUserPrefs(model.getUserPrefs());
} catch (IOException e) {
diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/seedu/workbook/commons/core/Config.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/Config.java
rename to src/main/java/seedu/workbook/commons/core/Config.java
index 91145745521..63b9001631d 100644
--- a/src/main/java/seedu/address/commons/core/Config.java
+++ b/src/main/java/seedu/workbook/commons/core/Config.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.workbook.commons.core;
import java.nio.file.Path;
import java.nio.file.Paths;
diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/workbook/commons/core/GuiSettings.java
similarity index 98%
rename from src/main/java/seedu/address/commons/core/GuiSettings.java
rename to src/main/java/seedu/workbook/commons/core/GuiSettings.java
index ba33653be67..53c7c5e8644 100644
--- a/src/main/java/seedu/address/commons/core/GuiSettings.java
+++ b/src/main/java/seedu/workbook/commons/core/GuiSettings.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.workbook.commons.core;
import java.awt.Point;
import java.io.Serializable;
diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/workbook/commons/core/LogsCenter.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/LogsCenter.java
rename to src/main/java/seedu/workbook/commons/core/LogsCenter.java
index 431e7185e76..0c1bf219a26 100644
--- a/src/main/java/seedu/address/commons/core/LogsCenter.java
+++ b/src/main/java/seedu/workbook/commons/core/LogsCenter.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.workbook.commons.core;
import java.io.IOException;
import java.util.Arrays;
@@ -18,7 +18,7 @@
public class LogsCenter {
private static final int MAX_FILE_COUNT = 5;
private static final int MAX_FILE_SIZE_IN_BYTES = (int) (Math.pow(2, 20) * 5); // 5MB
- private static final String LOG_FILE = "addressbook.log";
+ private static final String LOG_FILE = "workbook.log";
private static Level currentLogLevel = Level.INFO;
private static final Logger logger = LogsCenter.getLogger(LogsCenter.class);
private static FileHandler fileHandler;
diff --git a/src/main/java/seedu/workbook/commons/core/Messages.java b/src/main/java/seedu/workbook/commons/core/Messages.java
new file mode 100644
index 00000000000..d9ea0952786
--- /dev/null
+++ b/src/main/java/seedu/workbook/commons/core/Messages.java
@@ -0,0 +1,13 @@
+package seedu.workbook.commons.core;
+
+/**
+ * Container for user visible messages.
+ */
+public class Messages {
+
+ public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
+ public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
+ public static final String MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX = "The internship index provided is invalid";
+ public static final String MESSAGE_INTERNSHIPS_LISTED_OVERVIEW = "%1$d internships listed!";
+
+}
diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/seedu/workbook/commons/core/Version.java
similarity index 98%
rename from src/main/java/seedu/address/commons/core/Version.java
rename to src/main/java/seedu/workbook/commons/core/Version.java
index 12142ec1e32..48e15d96cb7 100644
--- a/src/main/java/seedu/address/commons/core/Version.java
+++ b/src/main/java/seedu/workbook/commons/core/Version.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.workbook.commons.core;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/src/main/java/seedu/address/commons/core/index/Index.java b/src/main/java/seedu/workbook/commons/core/index/Index.java
similarity index 88%
rename from src/main/java/seedu/address/commons/core/index/Index.java
rename to src/main/java/seedu/workbook/commons/core/index/Index.java
index 19536439c09..db4f996b6ba 100644
--- a/src/main/java/seedu/address/commons/core/index/Index.java
+++ b/src/main/java/seedu/workbook/commons/core/index/Index.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core.index;
+package seedu.workbook.commons.core.index;
/**
* Represents a zero-based or one-based index.
@@ -33,6 +33,8 @@ public int getOneBased() {
/**
* Creates a new {@code Index} using a zero-based index.
+ * @param zeroBasedIndex Index from a zero-based indexing.
+ * @return Index
*/
public static Index fromZeroBased(int zeroBasedIndex) {
return new Index(zeroBasedIndex);
@@ -40,6 +42,8 @@ public static Index fromZeroBased(int zeroBasedIndex) {
/**
* Creates a new {@code Index} using a one-based index.
+ * @param oneBasedIndex Index from a one-based indexing
+ * @return Index
*/
public static Index fromOneBased(int oneBasedIndex) {
return new Index(oneBasedIndex - 1);
diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/seedu/workbook/commons/exceptions/DataConversionException.java
similarity index 84%
rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java
rename to src/main/java/seedu/workbook/commons/exceptions/DataConversionException.java
index 1f689bd8e3f..7b3e3387146 100644
--- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java
+++ b/src/main/java/seedu/workbook/commons/exceptions/DataConversionException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package seedu.workbook.commons.exceptions;
/**
* Represents an error during conversion of data from one format to another
diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/seedu/workbook/commons/exceptions/IllegalValueException.java
similarity index 92%
rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
rename to src/main/java/seedu/workbook/commons/exceptions/IllegalValueException.java
index 19124db485c..105c7def179 100644
--- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
+++ b/src/main/java/seedu/workbook/commons/exceptions/IllegalValueException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package seedu.workbook.commons.exceptions;
/**
* Signals that some given data does not fulfill some constraints.
diff --git a/src/main/java/seedu/address/commons/util/AppUtil.java b/src/main/java/seedu/workbook/commons/util/AppUtil.java
similarity index 80%
rename from src/main/java/seedu/address/commons/util/AppUtil.java
rename to src/main/java/seedu/workbook/commons/util/AppUtil.java
index 87aa89c0326..550cb890cb5 100644
--- a/src/main/java/seedu/address/commons/util/AppUtil.java
+++ b/src/main/java/seedu/workbook/commons/util/AppUtil.java
@@ -1,9 +1,9 @@
-package seedu.address.commons.util;
+package seedu.workbook.commons.util;
import static java.util.Objects.requireNonNull;
import javafx.scene.image.Image;
-import seedu.address.MainApp;
+import seedu.workbook.MainApp;
/**
* A container for App specific utility functions
@@ -20,7 +20,7 @@ public static Image getImage(String imagePath) {
/**
* Checks that {@code condition} is true. Used for validating arguments to methods.
- *
+ * @param condition Boolean condition to be checked.
* @throws IllegalArgumentException if {@code condition} is false.
*/
public static void checkArgument(Boolean condition) {
@@ -31,7 +31,8 @@ public static void checkArgument(Boolean condition) {
/**
* Checks that {@code condition} is true. Used for validating arguments to methods.
- *
+ * @param condition Boolean condition to be checked.
+ * @param errorMessage Error message returned if {@code condition} is false.
* @throws IllegalArgumentException with {@code errorMessage} if {@code condition} is false.
*/
public static void checkArgument(Boolean condition, String errorMessage) {
diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/seedu/workbook/commons/util/CollectionUtil.java
similarity index 84%
rename from src/main/java/seedu/address/commons/util/CollectionUtil.java
rename to src/main/java/seedu/workbook/commons/util/CollectionUtil.java
index eafe4dfd681..26b50a93ff6 100644
--- a/src/main/java/seedu/address/commons/util/CollectionUtil.java
+++ b/src/main/java/seedu/workbook/commons/util/CollectionUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.workbook.commons.util;
import static java.util.Objects.requireNonNull;
@@ -20,6 +20,7 @@ public static void requireAllNonNull(Object... items) {
/**
* Throws NullPointerException if {@code items} or any element of {@code items} is null.
+ * @param items Items of type Collection
*/
public static void requireAllNonNull(Collection> items) {
requireNonNull(items);
@@ -28,6 +29,8 @@ public static void requireAllNonNull(Collection> items) {
/**
* Returns true if {@code items} contain any elements that are non-null.
+ * @param items Items of type Object
+ * @return Boolean value checking for non-null items
*/
public static boolean isAnyNonNull(Object... items) {
return items != null && Arrays.stream(items).anyMatch(Objects::nonNull);
diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/seedu/workbook/commons/util/ConfigUtil.java
similarity index 77%
rename from src/main/java/seedu/address/commons/util/ConfigUtil.java
rename to src/main/java/seedu/workbook/commons/util/ConfigUtil.java
index f7f8a2bd44c..a41c1f93577 100644
--- a/src/main/java/seedu/address/commons/util/ConfigUtil.java
+++ b/src/main/java/seedu/workbook/commons/util/ConfigUtil.java
@@ -1,11 +1,11 @@
-package seedu.address.commons.util;
+package seedu.workbook.commons.util;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
-import seedu.address.commons.core.Config;
-import seedu.address.commons.exceptions.DataConversionException;
+import seedu.workbook.commons.core.Config;
+import seedu.workbook.commons.exceptions.DataConversionException;
/**
* A class for accessing the Config File.
diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/seedu/workbook/commons/util/FileUtil.java
similarity index 74%
rename from src/main/java/seedu/address/commons/util/FileUtil.java
rename to src/main/java/seedu/workbook/commons/util/FileUtil.java
index b1e2767cdd9..8d45a904898 100644
--- a/src/main/java/seedu/address/commons/util/FileUtil.java
+++ b/src/main/java/seedu/workbook/commons/util/FileUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.workbook.commons.util;
import java.io.IOException;
import java.nio.file.Files;
@@ -18,7 +18,7 @@ public static boolean isFileExists(Path file) {
}
/**
- * Returns true if {@code path} can be converted into a {@code Path} via {@link Paths#get(String)},
+ * Returns true if {@code path} can be converted into a {@code Path} via {@link Paths #get(String)},
* otherwise returns false.
* @param path A string representing the file path. Cannot be null.
*/
@@ -32,7 +32,8 @@ public static boolean isValidPath(String path) {
}
/**
- * Creates a file if it does not exist along with its missing parent directories.
+ * Creates a file if it does not exist.
+ * @param file File to be created.
* @throws IOException if the file or directory cannot be created.
*/
public static void createIfMissing(Path file) throws IOException {
@@ -43,6 +44,8 @@ public static void createIfMissing(Path file) throws IOException {
/**
* Creates a file if it does not exist along with its missing parent directories.
+ * @param file File to be created.
+ * @throws IOException if the file or directory cannot be created.
*/
public static void createFile(Path file) throws IOException {
if (Files.exists(file)) {
@@ -56,6 +59,8 @@ public static void createFile(Path file) throws IOException {
/**
* Creates parent directories of file if it has a parent directory
+ * @param file File to create parent directories.
+ * @throws IOException if the file or directory cannot be created.
*/
public static void createParentDirsOfFile(Path file) throws IOException {
Path parentDir = file.getParent();
@@ -66,7 +71,9 @@ public static void createParentDirsOfFile(Path file) throws IOException {
}
/**
- * Assumes file exists
+ * Reads from a file that exists.
+ * @param file File to be read from.
+ * @throws IOException if the file does not exist.
*/
public static String readFromFile(Path file) throws IOException {
return new String(Files.readAllBytes(file), CHARSET);
@@ -75,6 +82,9 @@ public static String readFromFile(Path file) throws IOException {
/**
* Writes given string to a file.
* Will create the file if it does not exist yet.
+ * @param file File to be written to.
+ * @param content String to write to file.
+ * @throws IOException if the file or directory cannot be created.
*/
public static void writeToFile(Path file, String content) throws IOException {
Files.write(file, content.getBytes(CHARSET));
diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/seedu/workbook/commons/util/JsonUtil.java
similarity index 97%
rename from src/main/java/seedu/address/commons/util/JsonUtil.java
rename to src/main/java/seedu/workbook/commons/util/JsonUtil.java
index 8ef609f055d..f20b2b36940 100644
--- a/src/main/java/seedu/address/commons/util/JsonUtil.java
+++ b/src/main/java/seedu/workbook/commons/util/JsonUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.workbook.commons.util;
import static java.util.Objects.requireNonNull;
@@ -20,8 +20,8 @@
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.commons.exceptions.DataConversionException;
/**
* Converts a Java object instance to JSON and vice versa
diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/workbook/commons/util/StringUtil.java
similarity index 76%
rename from src/main/java/seedu/address/commons/util/StringUtil.java
rename to src/main/java/seedu/workbook/commons/util/StringUtil.java
index 61cc8c9a1cb..719c5489007 100644
--- a/src/main/java/seedu/address/commons/util/StringUtil.java
+++ b/src/main/java/seedu/workbook/commons/util/StringUtil.java
@@ -1,7 +1,7 @@
-package seedu.address.commons.util;
+package seedu.workbook.commons.util;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
+import static seedu.workbook.commons.util.AppUtil.checkArgument;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -65,4 +65,22 @@ public static boolean isNonZeroUnsignedInteger(String s) {
return false;
}
}
+
+ /**
+ * Converts a String to PascalCase but with whitespace preserved.
+ */
+ public static String toPascalCase(String roleName) {
+ char[] chars = roleName.toLowerCase().toCharArray();
+ boolean isNotWhitespace = false;
+ for (int i = 0; i < chars.length; i++) {
+ if (!isNotWhitespace && Character.isLetter(chars[i])) {
+ chars[i] = Character.toUpperCase(chars[i]);
+ isNotWhitespace = true;
+
+ } else if (Character.isWhitespace(chars[i])) {
+ isNotWhitespace = false;
+ }
+ }
+ return String.valueOf(chars);
+ }
}
diff --git a/src/main/java/seedu/workbook/logic/Logic.java b/src/main/java/seedu/workbook/logic/Logic.java
new file mode 100644
index 00000000000..54a8397805d
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/Logic.java
@@ -0,0 +1,44 @@
+package seedu.workbook.logic;
+
+import java.nio.file.Path;
+
+import javafx.collections.ObservableList;
+import seedu.workbook.commons.core.GuiSettings;
+import seedu.workbook.logic.commands.CommandResult;
+import seedu.workbook.logic.commands.exceptions.CommandException;
+import seedu.workbook.logic.parser.exceptions.ParseException;
+import seedu.workbook.model.ReadOnlyWorkBook;
+import seedu.workbook.model.internship.Internship;
+
+/**
+ * API of the Logic component
+ */
+public interface Logic {
+ /**
+ * Executes the command and returns the result.
+ * @param commandText The command as entered by the user.
+ * @return the result of the command execution.
+ * @throws CommandException If an error occurs during command execution.
+ * @throws ParseException If an error occurs during parsing.
+ */
+ CommandResult execute(String commandText) throws CommandException, ParseException;
+
+ /**
+ * Returns the WorkBook.
+ *
+ * @see seedu.workbook.model.Model#getWorkBook()
+ */
+ ReadOnlyWorkBook getWorkBook();
+
+ /** Returns an unmodifiable view of the filtered list of internships */
+ ObservableList getFilteredInternshipList();
+
+ /** Returns the user prefs' work book file path. */
+ Path getWorkBookFilePath();
+
+ /** Returns the user prefs' GUI settings. */
+ GuiSettings getGuiSettings();
+
+ /** Set the user prefs' GUI settings. */
+ void setGuiSettings(GuiSettings guiSettings);
+}
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/workbook/logic/LogicManager.java
similarity index 56%
rename from src/main/java/seedu/address/logic/LogicManager.java
rename to src/main/java/seedu/workbook/logic/LogicManager.java
index 9d9c6d15bdc..9933a9ee340 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/workbook/logic/LogicManager.java
@@ -1,21 +1,21 @@
-package seedu.address.logic;
+package seedu.workbook.logic;
import java.io.IOException;
import java.nio.file.Path;
import java.util.logging.Logger;
import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.AddressBookParser;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.Model;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-import seedu.address.storage.Storage;
+import seedu.workbook.commons.core.GuiSettings;
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.logic.commands.Command;
+import seedu.workbook.logic.commands.CommandResult;
+import seedu.workbook.logic.commands.exceptions.CommandException;
+import seedu.workbook.logic.parser.WorkBookParser;
+import seedu.workbook.logic.parser.exceptions.ParseException;
+import seedu.workbook.model.Model;
+import seedu.workbook.model.ReadOnlyWorkBook;
+import seedu.workbook.model.internship.Internship;
+import seedu.workbook.storage.Storage;
/**
* The main LogicManager of the app.
@@ -26,7 +26,7 @@ public class LogicManager implements Logic {
private final Model model;
private final Storage storage;
- private final AddressBookParser addressBookParser;
+ private final WorkBookParser workBookParser;
/**
* Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}.
@@ -34,7 +34,7 @@ public class LogicManager implements Logic {
public LogicManager(Model model, Storage storage) {
this.model = model;
this.storage = storage;
- addressBookParser = new AddressBookParser();
+ workBookParser = new WorkBookParser();
}
@Override
@@ -42,11 +42,11 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
logger.info("----------------[USER COMMAND][" + commandText + "]");
CommandResult commandResult;
- Command command = addressBookParser.parseCommand(commandText);
+ Command command = workBookParser.parseCommand(commandText);
commandResult = command.execute(model);
try {
- storage.saveAddressBook(model.getAddressBook());
+ storage.saveWorkBook(model.getWorkBook());
} catch (IOException ioe) {
throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe);
}
@@ -55,18 +55,18 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
- return model.getAddressBook();
+ public ReadOnlyWorkBook getWorkBook() {
+ return model.getWorkBook();
}
@Override
- public ObservableList getFilteredPersonList() {
- return model.getFilteredPersonList();
+ public ObservableList getFilteredInternshipList() {
+ return model.getFilteredInternshipList();
}
@Override
- public Path getAddressBookFilePath() {
- return model.getAddressBookFilePath();
+ public Path getWorkBookFilePath() {
+ return model.getWorkBookFilePath();
}
@Override
diff --git a/src/main/java/seedu/workbook/logic/commands/AddCommand.java b/src/main/java/seedu/workbook/logic/commands/AddCommand.java
new file mode 100644
index 00000000000..ac4fcebf5fe
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/commands/AddCommand.java
@@ -0,0 +1,92 @@
+package seedu.workbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_DATETIME;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_LANGUAGE_TAG;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.workbook.model.internship.util.StageUtil.stagesWithTipsToString;
+
+import seedu.workbook.logic.commands.exceptions.CommandException;
+import seedu.workbook.model.Model;
+import seedu.workbook.model.internship.Internship;
+
+/**
+ * Adds an Internship to WorkBook.
+ */
+public class AddCommand extends Command {
+
+ /** Command word to execute the add command */
+ public static final String COMMAND_WORD = "add";
+
+ /** Help message to execute the add command */
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds an internship application to WorkBook.\n"
+ + "Parameters: "
+ + PREFIX_COMPANY + "COMPANY "
+ + PREFIX_ROLE + "ROLE "
+ + PREFIX_STAGE + "STAGE "
+ + "[" + PREFIX_DATETIME + "DATE AND TIME] "
+ + "[" + PREFIX_EMAIL + "EMAIL] "
+ + "[" + PREFIX_LANGUAGE_TAG + "PROGRAMMING LANGUAGE]... "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_COMPANY + "Meta "
+ + PREFIX_ROLE + "Software Engineer "
+ + PREFIX_STAGE + "Interview "
+ + PREFIX_DATETIME + "10-Dec-2022 12:10 "
+ + PREFIX_EMAIL + "hr@meta.com "
+ + PREFIX_LANGUAGE_TAG + "javascript "
+ + PREFIX_TAG + "MANGA "
+ + PREFIX_TAG + "frontend";
+
+ /** Message string displaying successful execution of the add command */
+ public static final String MESSAGE_SUCCESS = "New internship application added: %1$s, "
+ + "check out some tips for the stage!";
+
+ /** Message string displaying successful execution of the add command, but stage is not in our pre-defined list */
+ public static final String MESSAGE_SUCCESS_STAGE_NO_TIPS = "New internship application added: %1$s.\n"
+ + "However, do you mean " + stagesWithTipsToString() + " for the Stage? \nWe curated "
+ + "some nifty tips for those stages!";
+
+ /** Message string displaying error message for unsuccessful execution of the add command for a duplicate */
+ public static final String MESSAGE_DUPLICATE_INTERNSHIP = "This internship application already exists in WorkBook";
+
+ /** Internship to be added to work book */
+ private final Internship toAdd;
+
+ /**
+ * Creates an AddCommand to add the specified {@code Internship}
+ */
+ public AddCommand(Internship internship) {
+ requireNonNull(internship);
+ toAdd = internship;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.hasInternship(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_INTERNSHIP);
+ }
+
+ model.addInternship(toAdd);
+ model.commitWorkBook();
+
+ if (toAdd.stageHasNoTips()) {
+ return new CommandResult(String.format(MESSAGE_SUCCESS_STAGE_NO_TIPS, toAdd));
+ } else {
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddCommand // instanceof handles nulls
+ && toAdd.equals(((AddCommand) other).toAdd));
+ }
+}
diff --git a/src/main/java/seedu/workbook/logic/commands/ClearCommand.java b/src/main/java/seedu/workbook/logic/commands/ClearCommand.java
new file mode 100644
index 00000000000..a08930dd70f
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/commands/ClearCommand.java
@@ -0,0 +1,26 @@
+package seedu.workbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.workbook.model.Model;
+import seedu.workbook.model.WorkBook;
+
+/**
+ * Clears the WorkBook.
+ */
+public class ClearCommand extends Command {
+
+ /** Command word to execute the clear command */
+ public static final String COMMAND_WORD = "clear";
+
+ /** Message string displaying successful execution of the clear command */
+ public static final String MESSAGE_SUCCESS = "Work book has been cleared!";
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.setWorkBook(new WorkBook());
+ model.commitWorkBook();
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/workbook/logic/commands/Command.java
similarity index 78%
rename from src/main/java/seedu/address/logic/commands/Command.java
rename to src/main/java/seedu/workbook/logic/commands/Command.java
index 64f18992160..84e263777d7 100644
--- a/src/main/java/seedu/address/logic/commands/Command.java
+++ b/src/main/java/seedu/workbook/logic/commands/Command.java
@@ -1,7 +1,7 @@
-package seedu.address.logic.commands;
+package seedu.workbook.logic.commands;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
+import seedu.workbook.logic.commands.exceptions.CommandException;
+import seedu.workbook.model.Model;
/**
* Represents a command with hidden internal logic and the ability to be executed.
diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/workbook/logic/commands/CommandResult.java
similarity index 97%
rename from src/main/java/seedu/address/logic/commands/CommandResult.java
rename to src/main/java/seedu/workbook/logic/commands/CommandResult.java
index 92f900b7916..68e7523796d 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/workbook/logic/commands/CommandResult.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.commands;
+package seedu.workbook.logic.commands;
import static java.util.Objects.requireNonNull;
diff --git a/src/main/java/seedu/workbook/logic/commands/DeleteCommand.java b/src/main/java/seedu/workbook/logic/commands/DeleteCommand.java
new file mode 100644
index 00000000000..df5894a38bb
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/commands/DeleteCommand.java
@@ -0,0 +1,58 @@
+package seedu.workbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.workbook.commons.core.Messages;
+import seedu.workbook.commons.core.index.Index;
+import seedu.workbook.logic.commands.exceptions.CommandException;
+import seedu.workbook.model.Model;
+import seedu.workbook.model.internship.Internship;
+
+/**
+ * Deletes a internship identified using it's displayed index from the WorkBook.
+ */
+public class DeleteCommand extends Command {
+
+ /** Command word to execute the delete command */
+ public static final String COMMAND_WORD = "delete";
+
+ /** Help message to execute the delete command */
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the internship identified by the index number used in the displayed internship list.\n"
+ + "Parameters: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ /** Message string displaying successful execution of the delete command */
+ public static final String MESSAGE_DELETE_INTERNSHIP_SUCCESS = "Deleted Internship: %1$s";
+
+ /** Index of internship to be deleted */
+ private final Index targetIndex;
+
+ public DeleteCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredInternshipList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX);
+ }
+
+ Internship internshipToDelete = lastShownList.get(targetIndex.getZeroBased());
+ model.deleteInternship(internshipToDelete);
+ model.commitWorkBook();
+ return new CommandResult(String.format(MESSAGE_DELETE_INTERNSHIP_SUCCESS, internshipToDelete));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteCommand // instanceof handles nulls
+ && targetIndex.equals(((DeleteCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/workbook/logic/commands/EditCommand.java b/src/main/java/seedu/workbook/logic/commands/EditCommand.java
new file mode 100644
index 00000000000..2105f47c066
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/commands/EditCommand.java
@@ -0,0 +1,287 @@
+package seedu.workbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_DATETIME;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_LANGUAGE_TAG;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import seedu.workbook.commons.core.Messages;
+import seedu.workbook.commons.core.index.Index;
+import seedu.workbook.commons.util.CollectionUtil;
+import seedu.workbook.logic.commands.exceptions.CommandException;
+import seedu.workbook.model.Model;
+import seedu.workbook.model.internship.Company;
+import seedu.workbook.model.internship.DateTime;
+import seedu.workbook.model.internship.Email;
+import seedu.workbook.model.internship.Internship;
+import seedu.workbook.model.internship.Role;
+import seedu.workbook.model.internship.Stage;
+import seedu.workbook.model.tag.Tag;
+
+/**
+ * Edits the details of an existing internship in the WorkBook.
+ */
+public class EditCommand extends Command {
+
+ /** Command word to execute the edit command */
+ public static final String COMMAND_WORD = "edit";
+
+ /** Help message to execute the edit command */
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the internship identified "
+ + "by the index number used in the displayed internship list. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "[" + PREFIX_COMPANY + "COMPANY] "
+ + "[" + PREFIX_ROLE + "ROLE] "
+ + "[" + PREFIX_STAGE + "STAGE] "
+ + "[" + PREFIX_DATETIME + "DATE AND TIME] "
+ + "[" + PREFIX_EMAIL + "EMAIL] "
+ + "[" + PREFIX_LANGUAGE_TAG + "PROGRAMMING LANGUAGE]... "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_EMAIL + "johndoe@example.com";
+
+ /** Message string displaying successful execution of the edit command */
+ public static final String MESSAGE_EDIT_INTERNSHIP_SUCCESS = "Edited Internship: %1$s";
+
+ /**
+ * Message string displaying error message for unsuccessful execution of the edit command
+ * for invalid input field
+ */
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+
+ /**
+ * Message string displaying error message for unsuccessful execution of the edit command
+ * for a duplicate internship
+ */
+ public static final String MESSAGE_DUPLICATE_INTERNSHIP = "This internship already exists in the work book.";
+
+ /** Index of the internship to be edited */
+ private final Index index;
+
+ /** Description of edit */
+ private final EditInternshipDescriptor editInternshipDescriptor;
+
+ /**
+ * Updates an indexed internship in the filtered internship list.
+ * @param index of the internship in the filtered internship list to edit
+ * @param editInternshipDescriptor details to edit the internship with
+ */
+ public EditCommand(Index index, EditInternshipDescriptor editInternshipDescriptor) {
+ requireNonNull(index);
+ requireNonNull(editInternshipDescriptor);
+
+ this.index = index;
+ this.editInternshipDescriptor = new EditInternshipDescriptor(editInternshipDescriptor);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredInternshipList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX);
+ }
+
+ Internship internshipToEdit = lastShownList.get(index.getZeroBased());
+ Internship editedInternship = createEditedInternship(internshipToEdit, editInternshipDescriptor);
+
+ if (!internshipToEdit.isSameInternship(editedInternship) && model.hasInternship(editedInternship)) {
+ throw new CommandException(MESSAGE_DUPLICATE_INTERNSHIP);
+ }
+
+ model.setInternship(internshipToEdit, editedInternship);
+ // Doesnt make sense to me to reset the filtering after editing an internship
+ // its not that hard to just type list
+
+ // model.updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS);
+ model.commitWorkBook();
+ return new CommandResult(String.format(MESSAGE_EDIT_INTERNSHIP_SUCCESS, editedInternship));
+ }
+
+ /**
+ * Creates and returns a {@code Internship} with the details of
+ * {@code internshipToEdit} edited with {@code editInternshipDescriptor}.
+ */
+ private static Internship createEditedInternship(Internship internshipToEdit,
+ EditInternshipDescriptor editInternshipDescriptor) {
+ assert internshipToEdit != null;
+
+ Company updatedCompany = editInternshipDescriptor.getCompany().orElse(internshipToEdit.getCompany());
+ Role updatedRole = editInternshipDescriptor.getRole().orElse(internshipToEdit.getRole());
+ Email updatedEmail = editInternshipDescriptor.getEmail().orElse(internshipToEdit.getEmail());
+ Stage updatedStage = editInternshipDescriptor.getStage().orElse(internshipToEdit.getStage());
+ DateTime updatedDateTime = editInternshipDescriptor.getDate().orElse(internshipToEdit.getDateTime());
+ Set updatedLanguageTags = editInternshipDescriptor.getLanguageTags()
+ .orElse(internshipToEdit.getLanguageTags());
+ Set updatedTags = editInternshipDescriptor.getTags().orElse(internshipToEdit.getTags());
+
+ return new Internship(updatedCompany, updatedRole,
+ updatedEmail, updatedStage, updatedDateTime, updatedLanguageTags, updatedTags);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditCommand)) {
+ return false;
+ }
+
+ // state check
+ EditCommand e = (EditCommand) other;
+ return index.equals(e.index)
+ && editInternshipDescriptor.equals(e.editInternshipDescriptor);
+ }
+
+ /**
+ * Stores the details to edit the internship with. Each non-empty field value
+ * will replace the corresponding field value of the internship.
+ */
+ public static class EditInternshipDescriptor {
+ private Company company;
+ private Role role;
+ private Email email;
+ private Stage stage;
+ private DateTime dateTime;
+ private Set languageTags;
+ private Set tags;
+
+ public EditInternshipDescriptor() {
+ }
+
+ /**
+ * Copy constructor.
+ * A defensive copy of {@code tags} is used internally.
+ */
+ public EditInternshipDescriptor(EditInternshipDescriptor toCopy) {
+ setCompany(toCopy.company);
+ setRole(toCopy.role);
+ setEmail(toCopy.email);
+ setStage(toCopy.stage);
+ setDate(toCopy.dateTime);
+ setLanguageTags(toCopy.languageTags);
+ setTags(toCopy.tags);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(company, role, email, stage, dateTime, languageTags, tags);
+ }
+
+ public void setCompany(Company company) {
+ this.company = company;
+ }
+
+ public Optional getCompany() {
+ return Optional.ofNullable(company);
+ }
+
+ public void setRole(Role role) {
+ this.role = role;
+ }
+
+ public Optional getRole() {
+ return Optional.ofNullable(role);
+ }
+
+ public void setEmail(Email email) {
+ this.email = email;
+ }
+
+ public Optional getEmail() {
+ return Optional.ofNullable(email);
+ }
+ public void setStage(Stage stage) {
+ this.stage = stage;
+ }
+
+ public Optional getStage() {
+ return Optional.ofNullable(stage);
+ }
+
+ public void setDate(DateTime dateTime) {
+ this.dateTime = dateTime;
+ }
+
+ public Optional getDate() {
+ return Optional.ofNullable(dateTime);
+ }
+
+ /**
+ * Sets {@code languageTags} to this object's {@code languageTags}.
+ * A defensive copy of {@code languageTags} is used internally.
+ */
+ public void setLanguageTags(Set languageTags) {
+ this.languageTags = (languageTags != null) ? new HashSet<>(languageTags) : null;
+ }
+
+ /**
+ * Returns an unmodifiable language tag set, which throws
+ * {@code UnsupportedOperationException} if modification is attempted.
+ * Returns {@code Optional#empty()} if {@code tags} is null.
+ */
+ public Optional> getLanguageTags() {
+ return (languageTags != null) ? Optional.of(Collections.unmodifiableSet(languageTags)) : Optional.empty();
+ }
+
+
+ /**
+ * Sets {@code tags} to this object's {@code tags}.
+ * A defensive copy of {@code tags} is used internally.
+ */
+ public void setTags(Set tags) {
+ this.tags = (tags != null) ? new HashSet<>(tags) : null;
+ }
+
+ /**
+ * Returns an unmodifiable tag set, which throws
+ * {@code UnsupportedOperationException} if modification is attempted.
+ * Returns {@code Optional#empty()} if {@code tags} is null.
+ */
+ public Optional> getTags() {
+ return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditInternshipDescriptor)) {
+ return false;
+ }
+
+ // state check
+ EditInternshipDescriptor e = (EditInternshipDescriptor) other;
+
+ return getCompany().equals(e.getCompany())
+ && getRole().equals(e.getRole())
+ && getEmail().equals(e.getEmail())
+ && getStage().equals(e.getStage())
+ && getDate().equals(e.getDate())
+ && getLanguageTags().equals(e.getLanguageTags())
+ && getTags().equals(e.getTags());
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/workbook/logic/commands/ExitCommand.java
similarity index 59%
rename from src/main/java/seedu/address/logic/commands/ExitCommand.java
rename to src/main/java/seedu/workbook/logic/commands/ExitCommand.java
index 3dd85a8ba90..a365f428ed6 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/workbook/logic/commands/ExitCommand.java
@@ -1,15 +1,17 @@
-package seedu.address.logic.commands;
+package seedu.workbook.logic.commands;
-import seedu.address.model.Model;
+import seedu.workbook.model.Model;
/**
* Terminates the program.
*/
public class ExitCommand extends Command {
+ /** Command word to execute the exit command */
public static final String COMMAND_WORD = "exit";
- public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ...";
+ /** Message string displaying successful execution of the exit command */
+ public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting WorkBook as requested ...";
@Override
public CommandResult execute(Model model) {
diff --git a/src/main/java/seedu/workbook/logic/commands/FindCommand.java b/src/main/java/seedu/workbook/logic/commands/FindCommand.java
new file mode 100644
index 00000000000..ea0c9cf41a4
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/commands/FindCommand.java
@@ -0,0 +1,54 @@
+package seedu.workbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE;
+
+import java.util.function.Predicate;
+
+import seedu.workbook.commons.core.Messages;
+import seedu.workbook.model.Model;
+import seedu.workbook.model.internship.Internship;
+
+/**
+ * Finds and lists all internships in WorkBook whose company, role or stage name contains
+ * any of the argument keywords.
+ * Keyword matching is case insensitive.
+ */
+public class FindCommand extends Command {
+
+ /** Command word to execute the find command */
+ public static final String COMMAND_WORD = "find";
+
+ /** Help message to execute the find command */
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Finds all internships either by Company, Role or Stage using their respective prefix and "
+ + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ + "Parameters: " + PREFIX_COMPANY + "COMPANY "
+ + "| " + PREFIX_ROLE + "ROLE "
+ + "| " + PREFIX_STAGE + "STAGE\n"
+ + "Example: " + COMMAND_WORD + " " + PREFIX_COMPANY + "Meta";
+
+ /** Keyword to search for */
+ private final Predicate predicate;
+
+ public FindCommand(Predicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredInternshipList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_INTERNSHIPS_LISTED_OVERVIEW, model.getFilteredInternshipList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FindCommand // instanceof handles nulls
+ && predicate.equals(((FindCommand) other).predicate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/workbook/logic/commands/HelpCommand.java
similarity index 67%
rename from src/main/java/seedu/address/logic/commands/HelpCommand.java
rename to src/main/java/seedu/workbook/logic/commands/HelpCommand.java
index bf824f91bd0..07a5eaa9d6a 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/workbook/logic/commands/HelpCommand.java
@@ -1,17 +1,20 @@
-package seedu.address.logic.commands;
+package seedu.workbook.logic.commands;
-import seedu.address.model.Model;
+import seedu.workbook.model.Model;
/**
* Format full help instructions for every command for display.
*/
public class HelpCommand extends Command {
+ /** Command word to execute the help command */
public static final String COMMAND_WORD = "help";
+ /** Help message to execute the help command */
public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows program usage instructions.\n"
+ "Example: " + COMMAND_WORD;
+ /** Message string displaying successful execution of the help command */
public static final String SHOWING_HELP_MESSAGE = "Opened help window.";
@Override
diff --git a/src/main/java/seedu/workbook/logic/commands/ListCommand.java b/src/main/java/seedu/workbook/logic/commands/ListCommand.java
new file mode 100644
index 00000000000..8533139e6da
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/commands/ListCommand.java
@@ -0,0 +1,26 @@
+package seedu.workbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.model.Model.PREDICATE_SHOW_ALL_INTERNSHIPS;
+
+import seedu.workbook.model.Model;
+
+/**
+ * Lists all internships in the WorkBook to the user.
+ */
+public class ListCommand extends Command {
+
+ /** Command word to execute the list command */
+ public static final String COMMAND_WORD = "list";
+
+ /** Message string displaying successful execution of the list command */
+ public static final String MESSAGE_SUCCESS = "Listed all internships";
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/workbook/logic/commands/RedoCommand.java b/src/main/java/seedu/workbook/logic/commands/RedoCommand.java
new file mode 100644
index 00000000000..2aebb63c19b
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/commands/RedoCommand.java
@@ -0,0 +1,38 @@
+package seedu.workbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.model.Model.PREDICATE_SHOW_ALL_INTERNSHIPS;
+
+import seedu.workbook.logic.commands.exceptions.CommandException;
+import seedu.workbook.model.Model;
+
+/**
+ * Reverts the {@code model}'s WorkBook to its previously undone state.
+ */
+public class RedoCommand extends Command {
+
+ /** Command word to execute the redo command */
+ public static final String COMMAND_WORD = "redo";
+
+ /** Message string displaying successful execution of the redo command */
+ public static final String MESSAGE_SUCCESS = "Redo success!";
+
+ /**
+ * Message string displaying error message for unsuccessful execution of the redo command
+ * for a WorkBook with no commands to redo
+ */
+ public static final String MESSAGE_FAILURE = "No more commands to redo!";
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (!model.canRedoWorkBook()) {
+ throw new CommandException(MESSAGE_FAILURE);
+ }
+
+ model.redoWorkBook();
+ model.updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/workbook/logic/commands/UndoCommand.java b/src/main/java/seedu/workbook/logic/commands/UndoCommand.java
new file mode 100644
index 00000000000..06eeda631fb
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/commands/UndoCommand.java
@@ -0,0 +1,37 @@
+package seedu.workbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.workbook.logic.commands.exceptions.CommandException;
+import seedu.workbook.model.Model;
+
+/**
+ * Reverts the {@code model}'s WorkBook to its previous state.
+ */
+public class UndoCommand extends Command {
+
+ /** Command word to execute the undo command */
+ public static final String COMMAND_WORD = "undo";
+
+ /** Message string displaying successful execution of the undo command */
+ public static final String MESSAGE_SUCCESS = "Undo previous changes successful!";
+
+ /**
+ * Message string displaying error message for unsuccessful execution of the undo command
+ * for an unmodified WorkBook
+ */
+ public static final String MESSAGE_NO_CHANGES = "No previous changes to undo!";
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (!model.canUndoWorkBook()) {
+ throw new CommandException(MESSAGE_NO_CHANGES);
+ }
+
+ model.undoWorkBook();
+ model.updateFilteredInternshipList(Model.PREDICATE_SHOW_ALL_INTERNSHIPS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/seedu/workbook/logic/commands/exceptions/CommandException.java
similarity index 89%
rename from src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
rename to src/main/java/seedu/workbook/logic/commands/exceptions/CommandException.java
index a16bd14f2cd..e872c9ef6ac 100644
--- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
+++ b/src/main/java/seedu/workbook/logic/commands/exceptions/CommandException.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.commands.exceptions;
+package seedu.workbook.logic.commands.exceptions;
/**
* Represents an error which occurs during execution of a {@link Command}.
diff --git a/src/main/java/seedu/workbook/logic/parser/AddCommandParser.java b/src/main/java/seedu/workbook/logic/parser/AddCommandParser.java
new file mode 100644
index 00000000000..f2473fd5d69
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/parser/AddCommandParser.java
@@ -0,0 +1,89 @@
+package seedu.workbook.logic.parser;
+
+import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_DATETIME;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_LANGUAGE_TAG;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.workbook.model.internship.DateTime.EMPTY_DATETIME;
+import static seedu.workbook.model.internship.Email.EMPTY_EMAIL;
+
+import java.util.Set;
+import java.util.stream.Stream;
+
+import seedu.workbook.logic.commands.AddCommand;
+import seedu.workbook.logic.parser.exceptions.ParseException;
+import seedu.workbook.logic.parser.util.CheckedFunction;
+import seedu.workbook.model.internship.Company;
+import seedu.workbook.model.internship.DateTime;
+import seedu.workbook.model.internship.Email;
+import seedu.workbook.model.internship.Internship;
+import seedu.workbook.model.internship.Role;
+import seedu.workbook.model.internship.Stage;
+import seedu.workbook.model.tag.Tag;
+
+/**
+ * Parses input arguments and creates a new AddCommand object
+ */
+public class AddCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddCommand
+ * and returns an AddCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_COMPANY, PREFIX_ROLE,
+ PREFIX_EMAIL, PREFIX_STAGE, PREFIX_DATETIME, PREFIX_LANGUAGE_TAG, PREFIX_TAG);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_COMPANY, PREFIX_ROLE, PREFIX_STAGE)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
+ }
+
+ Company company = ParserUtil.parseCompany(argMultimap.getValue(PREFIX_COMPANY).get());
+ Role role = ParserUtil.parseRole(argMultimap.getValue(PREFIX_ROLE).get());
+ Email email = parseOptionalEmail(PREFIX_EMAIL, argMultimap, ParserUtil::parseEmail);
+ Stage stage = ParserUtil.parseStage(argMultimap.getValue(PREFIX_STAGE).get());
+ DateTime dateTime = parseOptionalDateTime(PREFIX_DATETIME, argMultimap, ParserUtil::parseDateTime);
+ Set languageTagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_LANGUAGE_TAG));
+ Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
+
+ Internship internship = new Internship(company, role, email, stage, dateTime, languageTagList, tagList);
+
+ return new AddCommand(internship);
+ }
+
+ /**
+ * 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());
+ }
+
+ // Adapted and changed from CS2103T-T10-4
+ // https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110
+ private DateTime parseOptionalDateTime(Prefix prefix, ArgumentMultimap argMultimap,
+ CheckedFunction parserFn) throws ParseException {
+ if (argMultimap.getValue(prefix).isPresent()) {
+ return parserFn.apply(argMultimap.getValue(prefix).get());
+ }
+ return EMPTY_DATETIME;
+ }
+
+ // Adapted and changed from CS2103T-T10-4
+ // https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110
+ private Email parseOptionalEmail(Prefix prefix, ArgumentMultimap argMultimap,
+ CheckedFunction parserFn) throws ParseException {
+ if (argMultimap.getValue(prefix).isPresent()) {
+ return parserFn.apply(argMultimap.getValue(prefix).get());
+ }
+ return EMPTY_EMAIL;
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java b/src/main/java/seedu/workbook/logic/parser/ArgumentMultimap.java
similarity index 98%
rename from src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
rename to src/main/java/seedu/workbook/logic/parser/ArgumentMultimap.java
index 954c8e18f8e..477b3a8999d 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
+++ b/src/main/java/seedu/workbook/logic/parser/ArgumentMultimap.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.workbook.logic.parser;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/seedu/workbook/logic/parser/ArgumentTokenizer.java
similarity index 92%
rename from src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
rename to src/main/java/seedu/workbook/logic/parser/ArgumentTokenizer.java
index 5c9aebfa488..102608d87b6 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
+++ b/src/main/java/seedu/workbook/logic/parser/ArgumentTokenizer.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.workbook.logic.parser;
import java.util.ArrayList;
import java.util.Arrays;
@@ -28,6 +28,17 @@ public static ArgumentMultimap tokenize(String argsString, Prefix... prefixes) {
return extractArguments(argsString, positions);
}
+ /**
+ * Returns the number of prefixes that the user has input in argsString.
+ *
+ * @param argsString Arguments string of the form: {@code preamble value value ...}
+ * @param prefixes Prefixes to find in the arguments string.
+ * @return Returns the number of prefixes.
+ */
+ public static int numberOfPrefixes(String argsString, Prefix... prefixes) {
+ return findAllPrefixPositions(argsString, prefixes).size();
+ }
+
/**
* Finds all zero-based prefix positions in the given arguments string.
*
@@ -41,6 +52,8 @@ private static List findAllPrefixPositions(String argsString, Pr
.collect(Collectors.toList());
}
+
+
/**
* {@see findAllPrefixPositions}
*/
diff --git a/src/main/java/seedu/workbook/logic/parser/CliSyntax.java b/src/main/java/seedu/workbook/logic/parser/CliSyntax.java
new file mode 100644
index 00000000000..bba53f3bcb7
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/parser/CliSyntax.java
@@ -0,0 +1,17 @@
+package seedu.workbook.logic.parser;
+
+/**
+ * Contains Command Line Interface (CLI) syntax definitions common to multiple commands
+ */
+public class CliSyntax {
+
+ /* Prefix definitions */
+ public static final Prefix PREFIX_COMPANY = new Prefix("c/");
+ public static final Prefix PREFIX_ROLE = new Prefix("r/");
+ public static final Prefix PREFIX_EMAIL = new Prefix("e/");
+ public static final Prefix PREFIX_STAGE = new Prefix("s/");
+ public static final Prefix PREFIX_DATETIME = new Prefix("d/");
+ public static final Prefix PREFIX_LANGUAGE_TAG = new Prefix("l/");
+ public static final Prefix PREFIX_TAG = new Prefix("t/");
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/workbook/logic/parser/DeleteCommandParser.java
similarity index 73%
rename from src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
rename to src/main/java/seedu/workbook/logic/parser/DeleteCommandParser.java
index 522b93081cc..083e6287de9 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ b/src/main/java/seedu/workbook/logic/parser/DeleteCommandParser.java
@@ -1,10 +1,10 @@
-package seedu.address.logic.parser;
+package seedu.workbook.logic.parser;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.DeleteCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.workbook.commons.core.index.Index;
+import seedu.workbook.logic.commands.DeleteCommand;
+import seedu.workbook.logic.parser.exceptions.ParseException;
/**
* Parses input arguments and creates a new DeleteCommand object
diff --git a/src/main/java/seedu/workbook/logic/parser/EditCommandParser.java b/src/main/java/seedu/workbook/logic/parser/EditCommandParser.java
new file mode 100644
index 00000000000..90028fa17e9
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/parser/EditCommandParser.java
@@ -0,0 +1,94 @@
+package seedu.workbook.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_DATETIME;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_LANGUAGE_TAG;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.Set;
+
+import seedu.workbook.commons.core.index.Index;
+import seedu.workbook.logic.commands.EditCommand;
+import seedu.workbook.logic.commands.EditCommand.EditInternshipDescriptor;
+import seedu.workbook.logic.parser.exceptions.ParseException;
+import seedu.workbook.model.tag.Tag;
+
+/**
+ * Parses input arguments and creates a new EditCommand object
+ */
+public class EditCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the
+ * EditCommand and returns an EditCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public EditCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_COMPANY, PREFIX_ROLE,
+ PREFIX_EMAIL, PREFIX_STAGE, PREFIX_DATETIME, PREFIX_LANGUAGE_TAG, PREFIX_TAG);
+
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
+ }
+
+ EditInternshipDescriptor editInternshipDescriptor = new EditInternshipDescriptor();
+ if (argMultimap.getValue(PREFIX_COMPANY).isPresent()) {
+ editInternshipDescriptor.setCompany(ParserUtil.parseCompany(argMultimap.getValue(PREFIX_COMPANY).get()));
+ }
+ if (argMultimap.getValue(PREFIX_ROLE).isPresent()) {
+ editInternshipDescriptor.setRole(ParserUtil.parseRole(argMultimap.getValue(PREFIX_ROLE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
+ editInternshipDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
+ }
+ if (argMultimap.getValue(PREFIX_STAGE).isPresent()) {
+ editInternshipDescriptor.setStage(ParserUtil.parseStage(argMultimap.getValue(PREFIX_STAGE).get()));
+ }
+
+ if (argMultimap.getValue(PREFIX_DATETIME).isPresent()) {
+ editInternshipDescriptor.setDate(ParserUtil.parseDateTime(argMultimap.getValue(PREFIX_DATETIME).get()));
+ }
+
+ parseTagsForEdit(argMultimap.getAllValues(PREFIX_LANGUAGE_TAG))
+ .ifPresent(editInternshipDescriptor::setLanguageTags);
+
+ parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editInternshipDescriptor::setTags);
+
+ if (!editInternshipDescriptor.isAnyFieldEdited()) {
+ throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
+ }
+
+ return new EditCommand(index, editInternshipDescriptor);
+ }
+
+ /**
+ * Parses {@code Collection tags} into a {@code Set} if
+ * {@code tags} is non-empty.
+ * If {@code tags} contain only one element which is an empty string, it will be
+ * parsed into a {@code Set} containing zero tags.
+ */
+ private Optional> parseTagsForEdit(Collection tags) throws ParseException {
+ assert tags != null;
+
+ if (tags.isEmpty()) {
+ return Optional.empty();
+ }
+ Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
+ return Optional.of(ParserUtil.parseTags(tagSet));
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/logic/parser/FindCommandParser.java b/src/main/java/seedu/workbook/logic/parser/FindCommandParser.java
new file mode 100644
index 00000000000..7755bbb9b3e
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/parser/FindCommandParser.java
@@ -0,0 +1,78 @@
+package seedu.workbook.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_COMPANY;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.workbook.logic.parser.CliSyntax.PREFIX_STAGE;
+
+import java.util.Arrays;
+
+import seedu.workbook.logic.commands.FindCommand;
+import seedu.workbook.logic.parser.exceptions.ParseException;
+import seedu.workbook.model.internship.CompanyContainsKeywordsPredicate;
+import seedu.workbook.model.internship.RoleContainsKeywordsPredicate;
+import seedu.workbook.model.internship.StageContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FindCommand object
+ */
+public class FindCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindCommand
+ * and returns a FindCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+
+
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_COMPANY, PREFIX_ROLE,
+ PREFIX_STAGE);
+
+ int numberOfPrefixes = ArgumentTokenizer.numberOfPrefixes(args, PREFIX_COMPANY, PREFIX_ROLE,
+ PREFIX_STAGE);
+
+ if (!argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+
+ } else if (numberOfPrefixes > 1) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+
+ } else if (argMultimap.getValue(PREFIX_COMPANY).isPresent()) {
+ String arguments = argMultimap.getValue(PREFIX_COMPANY).get();
+ if (arguments.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+ String[] companyNameKeywords = arguments.split("\\s+");
+ return new FindCommand(new CompanyContainsKeywordsPredicate(Arrays.asList(companyNameKeywords)));
+
+ } else if (argMultimap.getValue(PREFIX_STAGE).isPresent()) {
+ String arguments = argMultimap.getValue(PREFIX_STAGE).get();
+ if (arguments.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+ String[] stageKeywords = arguments.split("\\s+");
+ return new FindCommand(new StageContainsKeywordsPredicate(Arrays.asList(stageKeywords)));
+
+ } else if (argMultimap.getValue(PREFIX_ROLE).isPresent()) {
+ String arguments = argMultimap.getValue(PREFIX_ROLE).get();
+ if (arguments.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+ String[] roleKeywords = arguments.split("\\s+");
+ return new FindCommand(new RoleContainsKeywordsPredicate(Arrays.asList(roleKeywords)));
+
+ } else {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/Parser.java b/src/main/java/seedu/workbook/logic/parser/Parser.java
similarity index 72%
rename from src/main/java/seedu/address/logic/parser/Parser.java
rename to src/main/java/seedu/workbook/logic/parser/Parser.java
index d6551ad8e3f..210efac3b52 100644
--- a/src/main/java/seedu/address/logic/parser/Parser.java
+++ b/src/main/java/seedu/workbook/logic/parser/Parser.java
@@ -1,7 +1,7 @@
-package seedu.address.logic.parser;
+package seedu.workbook.logic.parser;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.workbook.logic.commands.Command;
+import seedu.workbook.logic.parser.exceptions.ParseException;
/**
* Represents a Parser that is able to parse user input into a {@code Command} of type {@code T}.
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/workbook/logic/parser/ParserUtil.java
similarity index 51%
rename from src/main/java/seedu/address/logic/parser/ParserUtil.java
rename to src/main/java/seedu/workbook/logic/parser/ParserUtil.java
index b117acb9c55..8b281125dd2 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/workbook/logic/parser/ParserUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.workbook.logic.parser;
import static java.util.Objects.requireNonNull;
@@ -6,14 +6,15 @@
import java.util.HashSet;
import java.util.Set;
-import seedu.address.commons.core.index.Index;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.workbook.commons.core.index.Index;
+import seedu.workbook.commons.util.StringUtil;
+import seedu.workbook.logic.parser.exceptions.ParseException;
+import seedu.workbook.model.internship.Company;
+import seedu.workbook.model.internship.DateTime;
+import seedu.workbook.model.internship.Email;
+import seedu.workbook.model.internship.Role;
+import seedu.workbook.model.internship.Stage;
+import seedu.workbook.model.tag.Tag;
/**
* Contains utility methods used for parsing strings in the various *Parser classes.
@@ -36,49 +37,35 @@ public static Index parseIndex(String oneBasedIndex) throws ParseException {
}
/**
- * Parses a {@code String name} into a {@code Name}.
+ * Parses a {@code String company} into a {@code Company}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code name} is invalid.
+ * @throws ParseException if the given {@code company} is invalid.
*/
- public static Name parseName(String name) throws ParseException {
- requireNonNull(name);
- String trimmedName = name.trim();
- if (!Name.isValidName(trimmedName)) {
- throw new ParseException(Name.MESSAGE_CONSTRAINTS);
+ public static Company parseCompany(String company) throws ParseException {
+ requireNonNull(company);
+ String trimmedCompany = company.trim();
+ if (!Company.isValidCompany(trimmedCompany)) {
+ throw new ParseException(Company.MESSAGE_CONSTRAINTS);
}
- return new Name(trimmedName);
+ return new Company(trimmedCompany);
}
/**
- * Parses a {@code String phone} into a {@code Phone}.
+ * Parses a {@code String role} into a {@code Role}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code phone} is invalid.
+ * @throws ParseException if the given {@code role} is invalid.
*/
- public static Phone parsePhone(String phone) throws ParseException {
- requireNonNull(phone);
- String trimmedPhone = phone.trim();
- if (!Phone.isValidPhone(trimmedPhone)) {
- throw new ParseException(Phone.MESSAGE_CONSTRAINTS);
+ public static Role parseRole(String role) throws ParseException {
+ requireNonNull(role);
+ String trimmedRole = role.trim();
+ if (!Role.isValidRole(trimmedRole)) {
+ throw new ParseException(Role.MESSAGE_CONSTRAINTS);
}
- return new Phone(trimmedPhone);
+ return new Role(trimmedRole);
}
- /**
- * Parses a {@code String address} into an {@code Address}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code address} is invalid.
- */
- public static Address parseAddress(String address) throws ParseException {
- requireNonNull(address);
- String trimmedAddress = address.trim();
- if (!Address.isValidAddress(trimmedAddress)) {
- throw new ParseException(Address.MESSAGE_CONSTRAINTS);
- }
- return new Address(trimmedAddress);
- }
/**
* Parses a {@code String email} into an {@code Email}.
@@ -95,18 +82,45 @@ public static Email parseEmail(String email) throws ParseException {
return new Email(trimmedEmail);
}
+ /**
+ * Parses a {@code String stage} into an {@code Stage}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code stage} is invalid.
+ */
+ public static Stage parseStage(String stage) throws ParseException {
+ requireNonNull(stage);
+ String trimmedStage = stage.trim();
+ if (!Stage.isValidStage(trimmedStage)) {
+ throw new ParseException(Stage.MESSAGE_CONSTRAINTS);
+ }
+ return new Stage(trimmedStage);
+ }
+
+ /**
+ * Parses a {@code String date} into a {@code DateTime}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code dateTime} is invalid.
+ */
+ public static DateTime parseDateTime(String dateTime) throws ParseException {
+ requireNonNull(dateTime);
+ String trimmedDateTime = dateTime.trim();
+ if (!DateTime.isValidDateTime(trimmedDateTime)) {
+ throw new ParseException(DateTime.MESSAGE_CONSTRAINTS);
+ }
+ return new DateTime(trimmedDateTime);
+ }
+
/**
* Parses a {@code String tag} into a {@code Tag}.
* Leading and trailing whitespaces will be trimmed.
*
* @throws ParseException if the given {@code tag} is invalid.
*/
- public static Tag parseTag(String tag) throws ParseException {
+ public static Tag parseTag(String tag) {
requireNonNull(tag);
String trimmedTag = tag.trim();
- if (!Tag.isValidTagName(trimmedTag)) {
- throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
- }
return new Tag(trimmedTag);
}
@@ -117,6 +131,9 @@ public static Set parseTags(Collection tags) throws ParseException
requireNonNull(tags);
final Set tagSet = new HashSet<>();
for (String tagName : tags) {
+ if (tagName.isBlank()) {
+ continue;
+ }
tagSet.add(parseTag(tagName));
}
return tagSet;
diff --git a/src/main/java/seedu/address/logic/parser/Prefix.java b/src/main/java/seedu/workbook/logic/parser/Prefix.java
similarity index 95%
rename from src/main/java/seedu/address/logic/parser/Prefix.java
rename to src/main/java/seedu/workbook/logic/parser/Prefix.java
index c859d5fa5db..f80215b89f4 100644
--- a/src/main/java/seedu/address/logic/parser/Prefix.java
+++ b/src/main/java/seedu/workbook/logic/parser/Prefix.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.workbook.logic.parser;
/**
* A prefix that marks the beginning of an argument in an arguments string.
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/workbook/logic/parser/WorkBookParser.java
similarity index 64%
rename from src/main/java/seedu/address/logic/parser/AddressBookParser.java
rename to src/main/java/seedu/workbook/logic/parser/WorkBookParser.java
index 1e466792b46..4dc73b2f42a 100644
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/workbook/logic/parser/WorkBookParser.java
@@ -1,26 +1,28 @@
-package seedu.address.logic.parser;
+package seedu.workbook.logic.parser;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+import static seedu.workbook.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.workbook.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.ClearCommand;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.DeleteCommand;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.ExitCommand;
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.logic.commands.HelpCommand;
-import seedu.address.logic.commands.ListCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.workbook.logic.commands.AddCommand;
+import seedu.workbook.logic.commands.ClearCommand;
+import seedu.workbook.logic.commands.Command;
+import seedu.workbook.logic.commands.DeleteCommand;
+import seedu.workbook.logic.commands.EditCommand;
+import seedu.workbook.logic.commands.ExitCommand;
+import seedu.workbook.logic.commands.FindCommand;
+import seedu.workbook.logic.commands.HelpCommand;
+import seedu.workbook.logic.commands.ListCommand;
+import seedu.workbook.logic.commands.RedoCommand;
+import seedu.workbook.logic.commands.UndoCommand;
+import seedu.workbook.logic.parser.exceptions.ParseException;
/**
* Parses user input.
*/
-public class AddressBookParser {
+public class WorkBookParser {
/**
* Used for initial separation of command word and args.
@@ -62,6 +64,12 @@ public Command parseCommand(String userInput) throws ParseException {
case ListCommand.COMMAND_WORD:
return new ListCommand();
+ case UndoCommand.COMMAND_WORD:
+ return new UndoCommand();
+
+ case RedoCommand.COMMAND_WORD:
+ return new RedoCommand();
+
case ExitCommand.COMMAND_WORD:
return new ExitCommand();
diff --git a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java b/src/main/java/seedu/workbook/logic/parser/exceptions/ParseException.java
similarity index 72%
rename from src/main/java/seedu/address/logic/parser/exceptions/ParseException.java
rename to src/main/java/seedu/workbook/logic/parser/exceptions/ParseException.java
index 158a1a54c1c..9c9fd28d9b6 100644
--- a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java
+++ b/src/main/java/seedu/workbook/logic/parser/exceptions/ParseException.java
@@ -1,6 +1,6 @@
-package seedu.address.logic.parser.exceptions;
+package seedu.workbook.logic.parser.exceptions;
-import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.workbook.commons.exceptions.IllegalValueException;
/**
* Represents a parse error encountered by a parser.
diff --git a/src/main/java/seedu/workbook/logic/parser/util/CheckedFunction.java b/src/main/java/seedu/workbook/logic/parser/util/CheckedFunction.java
new file mode 100644
index 00000000000..664fdacbc80
--- /dev/null
+++ b/src/main/java/seedu/workbook/logic/parser/util/CheckedFunction.java
@@ -0,0 +1,16 @@
+package seedu.workbook.logic.parser.util;
+
+import seedu.workbook.logic.parser.exceptions.ParseException;
+
+// Reused from CS2103T-T10-4
+// https://github.com/AY2223S1-CS2103T-T10-4/tp/commit/118c73f20a9eac789f37778a2f05e225f76a1110
+/**
+ * This is a functional interface which represents a function that can throw {@code ParseException}.
+ *
+ * @param the type of the exception thrown by the function
+ * @param the type of the result of the function
+ */
+@FunctionalInterface
+public interface CheckedFunction {
+ R apply(T t) throws ParseException;
+}
diff --git a/src/main/java/seedu/workbook/model/Model.java b/src/main/java/seedu/workbook/model/Model.java
new file mode 100644
index 00000000000..46393f0e1a5
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/Model.java
@@ -0,0 +1,105 @@
+package seedu.workbook.model;
+
+import java.nio.file.Path;
+import java.util.function.Predicate;
+
+import javafx.collections.ObservableList;
+import seedu.workbook.commons.core.GuiSettings;
+import seedu.workbook.model.internship.Internship;
+
+
+/**
+ * The API of the Model component.
+ */
+public interface Model {
+ /** {@code Predicate} that always evaluate to true */
+ Predicate PREDICATE_SHOW_ALL_INTERNSHIPS = unused -> true;
+
+ /** Replaces user prefs data with the data in {@code userPrefs}. */
+ void setUserPrefs(ReadOnlyUserPrefs userPrefs);
+
+ /** Returns the user prefs. */
+ ReadOnlyUserPrefs getUserPrefs();
+
+ /** Returns the user prefs' GUI settings. */
+ GuiSettings getGuiSettings();
+
+ /** Sets the user prefs' GUI settings. */
+ void setGuiSettings(GuiSettings guiSettings);
+
+ /** Returns the user prefs' work book file path. */
+ Path getWorkBookFilePath();
+
+ /** Sets the user prefs' work book file path. */
+ void setWorkBookFilePath(Path workBookFilePath);
+
+ /** Replaces work book data with the data in {@code workBook}. */
+ void setWorkBook(ReadOnlyWorkBook workBook);
+
+ /** Returns the WorkBook. */
+ ReadOnlyWorkBook getWorkBook();
+
+ /**
+ * Returns true if an Internship with the same identity as {@code internship}
+ * exists in WorkBook.
+ */
+ boolean hasInternship(Internship internship);
+
+ /**
+ * Deletes the given Internship.
+ * The internship must exist in WorkBook.
+ */
+ void deleteInternship(Internship target);
+
+ /**
+ * Adds the given Internship.
+ * {@code internship} must not already exist in the WorkBook.
+ */
+ void addInternship(Internship internship);
+
+ /**
+ * Replaces the given internship {@code target} with {@code editedInternship}.
+ * {@code target} must exist in WorkBook.
+ * The Internship identity of {@code editedInternship} must not be the same as
+ * another existing internship in WorkBook.
+ */
+ void setInternship(Internship target, Internship editedInternship);
+
+ /** Returns an unmodifiable view of the filtered internship list */
+ ObservableList getFilteredInternshipList();
+
+ /**
+ * Returns true if the model has undone WorkBook states to restore.
+ */
+ boolean canUndoWorkBook();
+
+ /**
+ * Returns true if the model has undone WorkBook states to restore.
+ */
+ boolean canRedoWorkBook();
+
+ /**
+ * Restores the model's WorkBook back to its previous state.
+ */
+ void undoWorkBook();
+
+ /**
+ * Restores the model's WorkBook to its previously undone state.
+ */
+ void redoWorkBook();
+
+ /**
+ * Saves the current WorkBook state for undo.
+ */
+ void commitWorkBook();
+
+ /**
+ * Updates the filter of the filtered internship list to filter by the given
+ * {@code predicate}.
+ *
+ * @throws NullPointerException if {@code predicate} is null.
+ */
+ void updateFilteredInternshipList(Predicate predicate);
+
+
+}
diff --git a/src/main/java/seedu/workbook/model/ModelManager.java b/src/main/java/seedu/workbook/model/ModelManager.java
new file mode 100644
index 00000000000..94245fc539c
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/ModelManager.java
@@ -0,0 +1,177 @@
+package seedu.workbook.model;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.nio.file.Path;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import javafx.collections.transformation.FilteredList;
+import seedu.workbook.commons.core.GuiSettings;
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.model.internship.Internship;
+
+/**
+ * Represents the in-memory model of the WorkBook data.
+ */
+public class ModelManager implements Model {
+ private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
+
+ private final VersionedWorkBook versionedWorkBook;
+ private final UserPrefs userPrefs;
+ private final FilteredList filteredInternships;
+
+ /**
+ * Initializes a ModelManager with the given WorkBook and userPrefs.
+ */
+ public ModelManager(ReadOnlyWorkBook workBook, ReadOnlyUserPrefs userPrefs) {
+ requireAllNonNull(workBook, userPrefs);
+
+ logger.fine("Initializing with work book: " + workBook + " and user prefs " + userPrefs);
+
+ versionedWorkBook = new VersionedWorkBook(workBook);
+ this.userPrefs = new UserPrefs(userPrefs);
+ filteredInternships = new FilteredList<>(this.versionedWorkBook.getInternshipList());
+ }
+
+ public ModelManager() {
+ this(new WorkBook(), new UserPrefs());
+ }
+
+ //=========== UserPrefs ==================================================================================
+
+ @Override
+ public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
+ requireNonNull(userPrefs);
+ this.userPrefs.resetData(userPrefs);
+ }
+
+ @Override
+ public ReadOnlyUserPrefs getUserPrefs() {
+ return userPrefs;
+ }
+
+ @Override
+ public GuiSettings getGuiSettings() {
+ return userPrefs.getGuiSettings();
+ }
+
+ @Override
+ public void setGuiSettings(GuiSettings guiSettings) {
+ requireNonNull(guiSettings);
+ userPrefs.setGuiSettings(guiSettings);
+ }
+
+ @Override
+ public Path getWorkBookFilePath() {
+ return userPrefs.getWorkBookFilePath();
+ }
+
+ @Override
+ public void setWorkBookFilePath(Path workBookFilePath) {
+ requireNonNull(workBookFilePath);
+ userPrefs.setWorkBookFilePath(workBookFilePath);
+ }
+
+ //=========== WorkBook ================================================================================
+
+ @Override
+ public void setWorkBook(ReadOnlyWorkBook workBook) {
+ this.versionedWorkBook.resetData(workBook);
+ }
+
+ @Override
+ public ReadOnlyWorkBook getWorkBook() {
+ return versionedWorkBook;
+ }
+
+ @Override
+ public boolean hasInternship(Internship internship) {
+ requireNonNull(internship);
+ return versionedWorkBook.hasInternship(internship);
+ }
+
+ @Override
+ public void deleteInternship(Internship target) {
+ versionedWorkBook.removeInternship(target);
+ }
+
+ @Override
+ public void addInternship(Internship internship) {
+ versionedWorkBook.addInternship(internship);
+ // resets ui view to show all internships whenever add command is executed
+ // ideal behaviour TBD
+ updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS);
+ }
+
+ @Override
+ public void setInternship(Internship target, Internship editedInternship) {
+ requireAllNonNull(target, editedInternship);
+
+ versionedWorkBook.setInternship(target, editedInternship);
+ }
+
+ //=========== Filtered Internship List Accessors =============================================================
+
+ /**
+ * Returns an unmodifiable view of the list of {@code Internship} backed by the internal list of
+ * {@code versionedWorkBook}
+ */
+ @Override
+ public ObservableList getFilteredInternshipList() {
+ return filteredInternships;
+ }
+
+ @Override
+ public boolean canUndoWorkBook() {
+ return versionedWorkBook.canUndo();
+ }
+
+ @Override
+ public boolean canRedoWorkBook() {
+ return versionedWorkBook.canRedo();
+ }
+
+ @Override
+ public void undoWorkBook() {
+ versionedWorkBook.undo();
+ }
+
+ @Override
+ public void redoWorkBook() {
+ versionedWorkBook.redo();
+ }
+
+ @Override
+ public void commitWorkBook() {
+ versionedWorkBook.commit();
+ }
+
+ @Override
+ public void updateFilteredInternshipList(Predicate predicate) {
+ requireNonNull(predicate);
+ filteredInternships.setPredicate(predicate);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ // short circuit if same object
+ if (obj == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(obj instanceof ModelManager)) {
+ return false;
+ }
+
+ // state check
+ ModelManager other = (ModelManager) obj;
+ return versionedWorkBook.equals(other.versionedWorkBook)
+ && userPrefs.equals(other.userPrefs)
+ && filteredInternships.equals(other.filteredInternships);
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/seedu/workbook/model/ReadOnlyUserPrefs.java
similarity index 57%
rename from src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
rename to src/main/java/seedu/workbook/model/ReadOnlyUserPrefs.java
index befd58a4c73..14b337f16c7 100644
--- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
+++ b/src/main/java/seedu/workbook/model/ReadOnlyUserPrefs.java
@@ -1,8 +1,8 @@
-package seedu.address.model;
+package seedu.workbook.model;
import java.nio.file.Path;
-import seedu.address.commons.core.GuiSettings;
+import seedu.workbook.commons.core.GuiSettings;
/**
* Unmodifiable view of user prefs.
@@ -11,6 +11,6 @@ public interface ReadOnlyUserPrefs {
GuiSettings getGuiSettings();
- Path getAddressBookFilePath();
+ Path getWorkBookFilePath();
}
diff --git a/src/main/java/seedu/workbook/model/ReadOnlyWorkBook.java b/src/main/java/seedu/workbook/model/ReadOnlyWorkBook.java
new file mode 100644
index 00000000000..fb5fbb53c18
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/ReadOnlyWorkBook.java
@@ -0,0 +1,17 @@
+package seedu.workbook.model;
+
+import javafx.collections.ObservableList;
+import seedu.workbook.model.internship.Internship;
+
+/**
+ * Unmodifiable view of a WorkBook
+ */
+public interface ReadOnlyWorkBook {
+
+ /**
+ * Returns an unmodifiable view of the internships list.
+ * This list will not contain any duplicate internships.
+ */
+ ObservableList getInternshipList();
+
+}
diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/workbook/model/UserPrefs.java
similarity index 70%
rename from src/main/java/seedu/address/model/UserPrefs.java
rename to src/main/java/seedu/workbook/model/UserPrefs.java
index 25a5fd6eab9..095d85d64a4 100644
--- a/src/main/java/seedu/address/model/UserPrefs.java
+++ b/src/main/java/seedu/workbook/model/UserPrefs.java
@@ -1,4 +1,4 @@
-package seedu.address.model;
+package seedu.workbook.model;
import static java.util.Objects.requireNonNull;
@@ -6,7 +6,7 @@
import java.nio.file.Paths;
import java.util.Objects;
-import seedu.address.commons.core.GuiSettings;
+import seedu.workbook.commons.core.GuiSettings;
/**
* Represents User's preferences.
@@ -14,7 +14,7 @@
public class UserPrefs implements ReadOnlyUserPrefs {
private GuiSettings guiSettings = new GuiSettings();
- private Path addressBookFilePath = Paths.get("data" , "addressbook.json");
+ private Path workBookFilePath = Paths.get("data" , "workbook.json");
/**
* Creates a {@code UserPrefs} with default values.
@@ -35,7 +35,7 @@ public UserPrefs(ReadOnlyUserPrefs userPrefs) {
public void resetData(ReadOnlyUserPrefs newUserPrefs) {
requireNonNull(newUserPrefs);
setGuiSettings(newUserPrefs.getGuiSettings());
- setAddressBookFilePath(newUserPrefs.getAddressBookFilePath());
+ setWorkBookFilePath(newUserPrefs.getWorkBookFilePath());
}
public GuiSettings getGuiSettings() {
@@ -47,13 +47,14 @@ public void setGuiSettings(GuiSettings guiSettings) {
this.guiSettings = guiSettings;
}
- public Path getAddressBookFilePath() {
- return addressBookFilePath;
+ @Override
+ public Path getWorkBookFilePath() {
+ return workBookFilePath;
}
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- this.addressBookFilePath = addressBookFilePath;
+ public void setWorkBookFilePath(Path workBookFilePath) {
+ requireNonNull(workBookFilePath);
+ this.workBookFilePath = workBookFilePath;
}
@Override
@@ -68,19 +69,19 @@ public boolean equals(Object other) {
UserPrefs o = (UserPrefs) other;
return guiSettings.equals(o.guiSettings)
- && addressBookFilePath.equals(o.addressBookFilePath);
+ && workBookFilePath.equals(o.workBookFilePath);
}
@Override
public int hashCode() {
- return Objects.hash(guiSettings, addressBookFilePath);
+ return Objects.hash(guiSettings, workBookFilePath);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Gui Settings : " + guiSettings);
- sb.append("\nLocal data file location : " + addressBookFilePath);
+ sb.append("\nLocal data file location : " + workBookFilePath);
return sb.toString();
}
diff --git a/src/main/java/seedu/workbook/model/VersionedWorkBook.java b/src/main/java/seedu/workbook/model/VersionedWorkBook.java
new file mode 100644
index 00000000000..426bd4bb860
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/VersionedWorkBook.java
@@ -0,0 +1,114 @@
+//Solution below adapted from
+// https://github.com/se-edu/addressbook-level4/blob/master/src/main/java/seedu/address/model/VersionedAddressBook.java
+package seedu.workbook.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@code WorkBook} that keeps track of its own history.
+ */
+public class VersionedWorkBook extends WorkBook {
+
+ private final List workBookStateList;
+ private int currentStatePointer;
+
+ /**
+ * Creates a VersionedWorkBook using the Internships in the {@code initialState}
+ */
+ public VersionedWorkBook(ReadOnlyWorkBook initialState) {
+ super(initialState);
+
+ workBookStateList = new ArrayList<>();
+ workBookStateList.add(new WorkBook(initialState));
+ currentStatePointer = 0;
+ }
+
+ /**
+ * Saves a copy of the current {@code WorkBook} state at the end of the state list.
+ * Undone states are removed from the state list.
+ */
+ public void commit() {
+ removeStatesAfterCurrentPointer();
+ workBookStateList.add(new WorkBook(this));
+ currentStatePointer++;
+ }
+
+ private void removeStatesAfterCurrentPointer() {
+ workBookStateList.subList(currentStatePointer + 1, workBookStateList.size()).clear();
+ }
+
+ /**
+ * Restores the WorkBook to its previous state.
+ */
+ public void undo() {
+ if (!canUndo()) {
+ throw new NoUndoableStateException();
+ }
+ currentStatePointer--;
+ resetData(workBookStateList.get(currentStatePointer));
+ }
+
+ /**
+ * Restores the WorkBook to its previously undone state.
+ */
+ public void redo() {
+ if (!canRedo()) {
+ throw new NoRedoableStateException();
+ }
+ currentStatePointer++;
+ resetData(workBookStateList.get(currentStatePointer));
+ }
+
+ /**
+ * Returns true if {@code undo()} has WorkBook states to undo.
+ */
+ public boolean canUndo() {
+ return currentStatePointer > 0;
+ }
+
+ /**
+ * Returns true if {@code redo()} has WorkBook states to redo.
+ */
+ public boolean canRedo() {
+ return currentStatePointer < workBookStateList.size() - 1;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof VersionedWorkBook)) {
+ return false;
+ }
+
+ VersionedWorkBook otherVersionedAddressBook = (VersionedWorkBook) other;
+
+ // state check
+ return super.equals(otherVersionedAddressBook)
+ && workBookStateList.equals(otherVersionedAddressBook.workBookStateList)
+ && currentStatePointer == otherVersionedAddressBook.currentStatePointer;
+ }
+
+ /**
+ * Thrown when trying to {@code undo()} but can't.
+ */
+ public static class NoUndoableStateException extends RuntimeException {
+ private NoUndoableStateException() {
+ super("Current state pointer at the start of workBookState list, unable to undo changes.");
+ }
+ }
+
+ /**
+ * Thrown when trying to {@code redo()} but can't.
+ */
+ public static class NoRedoableStateException extends RuntimeException {
+ private NoRedoableStateException() {
+ super("Current state pointer at end of addressBookState list, unable to redo.");
+ }
+ }
+}
diff --git a/src/main/java/seedu/workbook/model/WorkBook.java b/src/main/java/seedu/workbook/model/WorkBook.java
new file mode 100644
index 00000000000..18cdb89e61a
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/WorkBook.java
@@ -0,0 +1,125 @@
+package seedu.workbook.model;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import javafx.collections.ObservableList;
+import seedu.workbook.model.internship.Internship;
+import seedu.workbook.model.internship.UniqueInternshipList;
+
+/**
+ * Wraps all data at the WorkBook level
+ * Duplicates are not allowed (by .isSameInternship comparison)
+ */
+public class WorkBook implements ReadOnlyWorkBook {
+
+ private final UniqueInternshipList internships;
+
+ /*
+ * The 'unusual' code block below is a non-static initialization block,
+ * sometimes used to avoid duplication between constructors.
+ * See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
+ *
+ * Note that non-static init blocks are not recommended to use.
+ * There are other ways to avoid duplication among constructors.
+ */
+ {
+ internships = new UniqueInternshipList();
+ }
+
+ public WorkBook() {
+ }
+
+ /**
+ * Creates an WorkBook using the Internships in the {@code toBeCopied}
+ */
+ public WorkBook(ReadOnlyWorkBook toBeCopied) {
+ this();
+ resetData(toBeCopied);
+ }
+
+ //// list overwrite operations
+
+ /**
+ * Replaces the contents of the internship list with {@code internships}.
+ * {@code internships} must not contain duplicate internships.
+ */
+ public void setInternships(List internships) {
+ this.internships.setInternships(internships);
+ }
+
+ /**
+ * Resets the existing data of this {@code WorkBook} with {@code newData}.
+ */
+ public void resetData(ReadOnlyWorkBook newData) {
+ requireNonNull(newData);
+
+ setInternships(newData.getInternshipList());
+ }
+
+ //// internship-level operations
+
+ /**
+ * Returns true if an internship with the same identity as {@code internship}
+ * exists in the work book.
+ */
+ public boolean hasInternship(Internship internship) {
+ requireNonNull(internship);
+ return internships.contains(internship);
+ }
+
+ /**
+ * Adds an internship to the work book.
+ * The internship must not already exist in the work book.
+ */
+ public void addInternship(Internship i) {
+ internships.add(i);
+ }
+
+ /**
+ * Replaces the given internship {@code target} in the list with
+ * {@code editedInternship}.
+ * {@code target} must exist in the work book.
+ * The internship identity of {@code editedInternship} must not be the same as
+ * another existing internship in the work book.
+ */
+ public void setInternship(Internship target, Internship editedInternship) {
+ requireNonNull(editedInternship);
+
+ internships.setInternship(target, editedInternship);
+ }
+
+ /**
+ * Removes {@code key} from this {@code WorkBook}.
+ * {@code key} must exist in the work book.
+ */
+ public void removeInternship(Internship key) {
+ internships.remove(key);
+ }
+
+ //// util methods
+
+ @Override
+ public String toString() {
+ return internships.asUnmodifiableObservableList().size() + " internship applications";
+ // TODO: refine later
+ }
+
+ @Override
+ public ObservableList getInternshipList() {
+ return internships.asUnmodifiableObservableList();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof WorkBook // instanceof handles nulls
+ && internships.equals(((WorkBook) other).internships));
+ }
+
+ @Override
+ public int hashCode() {
+ return internships.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/workbook/model/internship/Company.java b/src/main/java/seedu/workbook/model/internship/Company.java
new file mode 100644
index 00000000000..b91b9e1c645
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/Company.java
@@ -0,0 +1,64 @@
+package seedu.workbook.model.internship;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.commons.util.AppUtil.checkArgument;
+
+import seedu.workbook.commons.util.StringUtil;
+
+/**
+ * Represents an Internship's company in WorkBook.
+ * Guarantees: immutable; is valid as declared in
+ * {@link #isValidCompany(String)}
+ */
+public class Company {
+
+ // CHECKSTYLE.OFF: LineLength
+ public static final String MESSAGE_CONSTRAINTS = "Company names should only contain alphanumeric characters and spaces, and it should not be blank";
+ // CHECKSTYLE.ON: LineLength
+
+ /*
+ * The first character of the Company must not be a whitespace,
+ * otherwise " " (a blank string) becomes a valid input.
+ */
+ public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+
+ public final String name;
+
+ /**
+ * Constructs a {@code Company}.
+ *
+ * @param name A valid Company name.
+ */
+ public Company(String name) {
+ requireNonNull(name);
+ checkArgument(isValidCompany(name), MESSAGE_CONSTRAINTS);
+ String modifiedName = StringUtil.toPascalCase(name);
+ this.name = modifiedName;
+ }
+
+ /**
+ * Returns true if a given string is a valid Company Name.
+ */
+ public static boolean isValidCompany(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Company // instanceof handles nulls
+ && name.equals(((Company) other).name)); // state check
+ }
+
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/model/internship/CompanyContainsKeywordsPredicate.java b/src/main/java/seedu/workbook/model/internship/CompanyContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..3e745be390e
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/CompanyContainsKeywordsPredicate.java
@@ -0,0 +1,31 @@
+package seedu.workbook.model.internship;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.workbook.commons.util.StringUtil;
+
+/**
+ * Tests that a {@code Internship}'s {@code Company} matches any of the keywords given.
+ */
+public class CompanyContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public CompanyContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Internship internship) {
+ return keywords.stream()
+ .allMatch(keyword -> StringUtil.containsWordIgnoreCase(internship.getCompany().name, keyword));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof CompanyContainsKeywordsPredicate // instanceof handles nulls
+ && keywords.equals(((CompanyContainsKeywordsPredicate) other).keywords)); // state check
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/model/internship/DateTime.java b/src/main/java/seedu/workbook/model/internship/DateTime.java
new file mode 100644
index 00000000000..76a2e8c1c1e
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/DateTime.java
@@ -0,0 +1,97 @@
+package seedu.workbook.model.internship;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.commons.util.AppUtil.checkArgument;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.format.ResolverStyle;
+
+/**
+ * Represents a DateTime in WorkBook.
+ * Guarantees: immutable; name is valid as declared in {@link #isValidDateTime(String)}
+ */
+public class DateTime {
+ public static final DateTime EMPTY_DATETIME = new DateTime("");
+ public static final String MESSAGE_CONSTRAINTS = "Date should be formatted as dd-mmm-yyyy hh:mm,"
+ + " and should actually exist.";
+
+ private static final String datePattern = "d-MMM-uuuu HH:mm";
+ private static final DateTimeFormatterBuilder formatterBuilder = new DateTimeFormatterBuilder()
+ .parseCaseInsensitive()
+ .appendPattern(datePattern);
+ private static final DateTimeFormatter dateFormatter = formatterBuilder.toFormatter()
+ .withResolverStyle(ResolverStyle.STRICT);
+
+
+ public final String value;
+
+ /**
+ * Constructs a {@code DateTime}.
+ *
+ * @param dateTime A valid dateTime.
+ */
+ public DateTime(String dateTime) {
+ requireNonNull(dateTime);
+ if (!dateTime.isEmpty()) {
+ checkArgument(isValidDateTime(dateTime), MESSAGE_CONSTRAINTS);
+ String str = String.join(" ", dateTime.split("\\s+", 2));
+ this.value = LocalDateTime.parse(str, dateFormatter).format(dateFormatter);
+ } else {
+ this.value = "";
+ }
+ }
+
+ /**
+ * Returns true if a given string is a valid {@code DateTime}.
+ */
+ public static boolean isValidDateTime(String test) {
+ try {
+ if (test.isEmpty()) {
+ return true;
+ }
+ String str = String.join(" ", test.split("\\s+", 2));
+ LocalDateTime.parse(str, dateFormatter);
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Note that DateTimeParseException will be thrown if this is called on DateTime.EMPTY
+ */
+ public boolean isAfter(DateTime other) {
+ LocalDateTime thisDate = LocalDateTime.parse(this.value, dateFormatter);
+ LocalDateTime otherDate = LocalDateTime.parse(other.value, dateFormatter);
+ return thisDate.isAfter(otherDate);
+ }
+
+ /**
+ * Note that DateTimeParseException will be thrown if this is called on DateTime.EMPTY
+ */
+ public boolean isPast() {
+ LocalDateTime thisDate = LocalDateTime.parse(this.value, dateFormatter);
+ return LocalDateTime.now().isAfter(thisDate);
+ }
+
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DateTime // instanceof handles nulls
+ && value.equals(((DateTime) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/workbook/model/internship/Email.java
similarity index 90%
rename from src/main/java/seedu/address/model/person/Email.java
rename to src/main/java/seedu/workbook/model/internship/Email.java
index f866e7133de..40edc99ad5f 100644
--- a/src/main/java/seedu/address/model/person/Email.java
+++ b/src/main/java/seedu/workbook/model/internship/Email.java
@@ -1,14 +1,15 @@
-package seedu.address.model.person;
+package seedu.workbook.model.internship;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
+import static seedu.workbook.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's email in the address book.
+ * Represents a Person's email in the WorkBook.
* Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)}
*/
public class Email {
+ public static final Email EMPTY_EMAIL = new Email("");
private static final String SPECIAL_CHARACTERS = "+_.-";
public static final String MESSAGE_CONSTRAINTS = "Emails should be of the format local-part@domain "
+ "and adhere to the following constraints:\n"
@@ -48,6 +49,9 @@ public Email(String email) {
* Returns if a given string is a valid email.
*/
public static boolean isValidEmail(String test) {
+ if (test.isEmpty()) {
+ return true;
+ }
return test.matches(VALIDATION_REGEX);
}
diff --git a/src/main/java/seedu/workbook/model/internship/Internship.java b/src/main/java/seedu/workbook/model/internship/Internship.java
new file mode 100644
index 00000000000..83d0026ffbe
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/Internship.java
@@ -0,0 +1,162 @@
+package seedu.workbook.model.internship;
+
+import static seedu.workbook.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+import seedu.workbook.model.tag.Tag;
+
+/**
+ * Represents an Internship Application in WorkBook.
+ * Guarantees: details are present and not null, field values are validated, immutable.
+ */
+public class Internship {
+
+ // Identity fields
+ private final Company company;
+ private final Role role;
+ private final Email email;
+ private final Stage stage;
+ private final DateTime dateTime;
+
+ // Data fields
+
+ private final Set languageTags = new HashSet<>();
+ private final Set tags = new HashSet<>();
+
+ /**
+ * Every field must be present and not null.
+ */
+ public Internship(
+ Company company, Role role, Email email, Stage stage, DateTime dateTime,
+ Set languageTags, Set tags) {
+ requireAllNonNull(company, role, email, stage, dateTime, tags);
+ this.company = company;
+ this.role = role;
+ this.email = email;
+ this.stage = stage;
+ this.dateTime = dateTime;
+ this.languageTags.addAll(languageTags);
+ this.tags.addAll(tags);
+ }
+
+ public Company getCompany() {
+ return company;
+ }
+
+ public Role getRole() {
+ return role;
+ }
+
+
+ public Email getEmail() {
+ return email;
+ }
+ public Stage getStage() {
+ return stage;
+ }
+ public DateTime getDateTime() {
+ return dateTime;
+ }
+
+ /**
+ * Returns an immutable language tag set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ */
+ public Set getLanguageTags() {
+ return Collections.unmodifiableSet(languageTags);
+ }
+
+ /**
+ * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ */
+ public Set getTags() {
+ return Collections.unmodifiableSet(tags);
+ }
+
+ /**
+ * Returns true if both internships have the same company AND role.
+ * This defines a weaker notion of equality between two internships.
+ */
+ public boolean isSameInternship(Internship otherInternship) {
+ if (otherInternship == this) {
+ return true;
+ }
+
+ return otherInternship != null
+ && otherInternship.getCompany().equals(getCompany())
+ && otherInternship.getRole().equals(getRole());
+ }
+
+ public boolean stageHasNoTips() {
+ return this.getStage().hasNoTips();
+ }
+
+ /**
+ * Returns true if both internships have the same identity and data fields.
+ * This defines a stronger notion of equality between two internships.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Internship)) {
+ return false;
+ }
+
+ Internship otherInternship = (Internship) other;
+ return otherInternship.getCompany().equals(getCompany())
+ && otherInternship.getRole().equals(getRole())
+ && otherInternship.getEmail().equals(getEmail())
+ && otherInternship.getStage().equals(getStage())
+ && otherInternship.getDateTime().equals(getDateTime())
+ && otherInternship.getLanguageTags().equals(getLanguageTags())
+ && otherInternship.getTags().equals(getTags());
+ }
+
+ @Override
+ public int hashCode() {
+ // use this method for custom fields hashing instead of implementing your own
+ return Objects.hash(company, role, email, stage, dateTime, languageTags, tags);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(getCompany())
+ .append("; Role: ")
+ .append(getRole())
+ .append("; Stage: ")
+ .append(getStage());
+
+ if (!getDateTime().value.isEmpty()) {
+ builder.append("; Date: ")
+ .append(getDateTime());
+ }
+
+ if (!getEmail().value.isEmpty()) {
+ builder.append("; Email: ")
+ .append(getEmail());
+ }
+
+ Set languageTags = getLanguageTags();
+ if (!languageTags.isEmpty()) {
+ builder.append("; Language Tags: ");
+ languageTags.forEach(builder::append);
+ }
+
+ Set tags = getTags();
+ if (!tags.isEmpty()) {
+ builder.append("; Tags: ");
+ tags.forEach(builder::append);
+ }
+ return builder.toString();
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/model/internship/InternshipComparator.java b/src/main/java/seedu/workbook/model/internship/InternshipComparator.java
new file mode 100644
index 00000000000..76d7f234022
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/InternshipComparator.java
@@ -0,0 +1,34 @@
+package seedu.workbook.model.internship;
+
+import java.util.Comparator;
+
+/**
+ * Comparator used for sorting the Internship list by Date.
+ */
+public class InternshipComparator implements Comparator {
+
+ @Override
+ public int compare(Internship o1, Internship o2) {
+ DateTime o1DateTime = o1.getDateTime();
+ DateTime o2DateTime = o2.getDateTime();
+
+ if (o1DateTime.equals(DateTime.EMPTY_DATETIME)) {
+ return o2DateTime.equals(DateTime.EMPTY_DATETIME)
+ ? o1.getCompany().name.compareTo(o2.getCompany().name)
+ : o2DateTime.isPast()
+ ? -1
+ : 1;
+ }
+
+ if (o1DateTime.isPast()) {
+ return o2DateTime.equals(DateTime.EMPTY_DATETIME) || o2DateTime.isAfter(o1DateTime)
+ ? 1
+ : -1;
+ }
+
+ return (o2DateTime.equals(DateTime.EMPTY_DATETIME) || o2DateTime.isPast())
+ || o2DateTime.isAfter(o1DateTime)
+ ? -1
+ : 1;
+ }
+}
diff --git a/src/main/java/seedu/workbook/model/internship/Role.java b/src/main/java/seedu/workbook/model/internship/Role.java
new file mode 100644
index 00000000000..f0ffe55fe38
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/Role.java
@@ -0,0 +1,63 @@
+package seedu.workbook.model.internship;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.commons.util.AppUtil.checkArgument;
+
+import seedu.workbook.commons.util.StringUtil;
+
+/**
+ * Represents an Internship's role in WorkBook.
+ * Guarantees: immutable; is valid as declared in {@link #isValidRole(String)}
+ */
+public class Role {
+
+ // CHECKSTYLE.OFF: LineLength
+ public static final String MESSAGE_CONSTRAINTS = "Role titles should only contain alphanumeric characters and spaces, and it should not be blank";
+ // CHECKSTYLE.ON: LineLength
+
+ /*
+ * The first character of the Role must not be a whitespace,
+ * otherwise " " (a blank string) becomes a valid input.
+ */
+ public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+
+ public final String value;
+
+ /**
+ * Constructs a {@code Role}.
+ *
+ * @param role A valid Role title.
+ */
+ public Role(String role) {
+ requireNonNull(role);
+ checkArgument(isValidRole(role), MESSAGE_CONSTRAINTS);
+ String modifiedRole = StringUtil.toPascalCase(role);
+ value = modifiedRole;
+ }
+
+ /**
+ * Returns true if a given string is a valid Role.
+ */
+ public static boolean isValidRole(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Role // instanceof handles nulls
+ && value.equals(((Role) other).value)); // state check
+ }
+
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/model/internship/RoleContainsKeywordsPredicate.java b/src/main/java/seedu/workbook/model/internship/RoleContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..d68887df7ea
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/RoleContainsKeywordsPredicate.java
@@ -0,0 +1,31 @@
+package seedu.workbook.model.internship;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.workbook.commons.util.StringUtil;
+
+/**
+ * Tests that a {@code Internship}'s {@code Role} matches any of the keywords given.
+ */
+public class RoleContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public RoleContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Internship internship) {
+ return keywords.stream()
+ .allMatch(keyword -> StringUtil.containsWordIgnoreCase(internship.getRole().value, keyword));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof RoleContainsKeywordsPredicate // instanceof handles nulls
+ && keywords.equals(((RoleContainsKeywordsPredicate) other).keywords)); // state check
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/model/internship/Stage.java b/src/main/java/seedu/workbook/model/internship/Stage.java
new file mode 100644
index 00000000000..f00213e71cc
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/Stage.java
@@ -0,0 +1,71 @@
+package seedu.workbook.model.internship;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.commons.util.AppUtil.checkArgument;
+
+import seedu.workbook.commons.util.StringUtil;
+import seedu.workbook.model.internship.util.StageUtil;
+
+/**
+ * Represents an Internship's application stage in WorkBook.
+ * Guarantees: immutable; is valid as declared in {@link #isValidStage(String)}
+ */
+public class Stage {
+
+ // CHECKSTYLE.OFF: LineLength
+ public static final String MESSAGE_CONSTRAINTS = "Stage should only contain alphanumeric characters and spaces, and it should not be blank";
+ // CHECKSTYLE.ON: LineLength
+
+ /*
+ * The first character of the Stage must not be a whitespace,
+ * otherwise " " (a blank string) becomes a valid input.
+ */
+ public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+
+ public final String value;
+
+ /**
+ * Constructs a {@code Stage}.
+ *
+ * @param stage A valid Stage name.
+ */
+ public Stage(String stage) {
+ requireNonNull(stage);
+ checkArgument(isValidStage(stage), MESSAGE_CONSTRAINTS);
+ String modifiedStage = StringUtil.toPascalCase(stage);
+ value = modifiedStage;
+ }
+
+ /**
+ * Returns true if a given string is a valid stage.
+ */
+ public static boolean isValidStage(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ /**
+ * Returns true if a given stage does not have curated tips.
+ */
+ public boolean hasNoTips() {
+ return !StageUtil.stageHasTips(this);
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Stage // instanceof handles nulls
+ && value.equals(((Stage) other).value)); // state check
+ }
+
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/model/internship/StageContainsKeywordsPredicate.java b/src/main/java/seedu/workbook/model/internship/StageContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..04408d65245
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/StageContainsKeywordsPredicate.java
@@ -0,0 +1,31 @@
+package seedu.workbook.model.internship;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.workbook.commons.util.StringUtil;
+
+/**
+ * Tests that a {@code Internship}'s {@code Stage} matches any of the keywords given.
+ */
+public class StageContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public StageContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Internship internship) {
+ return keywords.stream()
+ .allMatch(keyword -> StringUtil.containsWordIgnoreCase(internship.getStage().value, keyword));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof StageContainsKeywordsPredicate // instanceof handles nulls
+ && keywords.equals(((StageContainsKeywordsPredicate) other).keywords)); // state check
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/model/internship/UniqueInternshipList.java b/src/main/java/seedu/workbook/model/internship/UniqueInternshipList.java
new file mode 100644
index 00000000000..4c5525e20c4
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/UniqueInternshipList.java
@@ -0,0 +1,160 @@
+package seedu.workbook.model.internship;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.workbook.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.collections.transformation.SortedList;
+import seedu.workbook.model.internship.exceptions.DuplicateInternshipException;
+import seedu.workbook.model.internship.exceptions.InternshipNotFoundException;
+
+/**
+ * A list of internships that enforces uniqueness between its elements and does
+ * not allow nulls.
+ * A internship is considered unique by comparing using
+ * {@code Internship#isSameInternship(Internship)}.
+ *
+ * As such, adding and updating of internships uses
+ * Internship#isSameInternship(Internship) for equality so as to ensure that the
+ * internship being added or updated is unique in terms of identity in the
+ * UniqueInternshipList.
+ *
+ * However, the removal of an internship uses Internship#equals(Object) so as to
+ * ensure that the internship with exactly the same fields will be removed.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see Internship#isSameInternship(Internship)
+ */
+public class UniqueInternshipList implements Iterable {
+
+ // All updates should be performed only on internalList
+ private final ObservableList internalList = FXCollections.observableArrayList();
+
+ // wrapper on internalList, is automatically updated whenever
+ // internalList is updated, and is always in sorted order w.r.t
+ // InternshipComparator
+ private final SortedList sortedInternalList = new SortedList<>(internalList,
+ new InternshipComparator());
+
+ // is observed by UI components/external objects
+ private final ObservableList unmodifiableSortedInternalList = FXCollections
+ .unmodifiableObservableList(sortedInternalList);
+
+ /**
+ * Returns true if the list contains an equivalent internship as the given
+ * argument.
+ */
+ public boolean contains(Internship toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameInternship);
+ }
+
+ /**
+ * Adds an Internship to the list.
+ * The Internship must not already exist in the list.
+ */
+ public void add(Internship toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateInternshipException();
+ }
+ internalList.add(toAdd);
+ }
+
+ /**
+ * Replaces the Internship {@code target} in the list with
+ * {@code editedInternship}.
+ * {@code target} must exist in the list.
+ * The Internship identity of {@code editedInternship} must not be the same as
+ * another existing Internship in the list.
+ */
+ public void setInternship(Internship target, Internship editedInternship) {
+ requireAllNonNull(target, editedInternship);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new InternshipNotFoundException();
+ }
+
+ if (!target.isSameInternship(editedInternship) && contains(editedInternship)) {
+ throw new DuplicateInternshipException();
+ }
+
+ internalList.set(index, editedInternship);
+ }
+
+ /**
+ * Removes the equivalent Internship from the list.
+ * The Internship must exist in the list.
+ */
+ public void remove(Internship toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new InternshipNotFoundException();
+ }
+ }
+
+ public void setInternships(UniqueInternshipList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ }
+
+ /**
+ * Replaces the contents of this list with {@code Internships}.
+ * {@code Internships} must not contain duplicate Internships.
+ */
+ public void setInternships(List internships) {
+ requireAllNonNull(internships);
+ if (!internshipsAreUnique(internships)) {
+ throw new DuplicateInternshipException();
+ }
+
+ internalList.setAll(internships);
+ }
+
+ /**
+ * Returns the sorted list as an unmodifiable {@code ObservableList}.
+ *
+ * @see seedu.workbook.ui.MainWindow#fillInnerParts()
+ * @see seedu.workbook.storage.JsonSerializableWorkBook#JsonSerializableWorkBook(ReadOnlyWorkBook)
+ */
+ public ObservableList asUnmodifiableObservableList() {
+ return unmodifiableSortedInternalList;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return internalList.iterator();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof UniqueInternshipList // instanceof handles nulls
+ && sortedInternalList.equals(((UniqueInternshipList) other).sortedInternalList));
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ /**
+ * Returns true if {@code internships} contains only unique internships.
+ */
+ private boolean internshipsAreUnique(List internships) {
+ for (int i = 0; i < internships.size() - 1; i++) {
+ for (int j = i + 1; j < internships.size(); j++) {
+ if (internships.get(i).isSameInternship(internships.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/seedu/workbook/model/internship/exceptions/DuplicateInternshipException.java b/src/main/java/seedu/workbook/model/internship/exceptions/DuplicateInternshipException.java
new file mode 100644
index 00000000000..2bbe7114a02
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/exceptions/DuplicateInternshipException.java
@@ -0,0 +1,11 @@
+package seedu.workbook.model.internship.exceptions;
+
+/**
+ * Signals that the operation will result in duplicate Internships (Internships
+ * are considered duplicates if they have the same identity).
+ */
+public class DuplicateInternshipException extends RuntimeException {
+ public DuplicateInternshipException() {
+ super("Operation would result in duplicate internship applications");
+ }
+}
diff --git a/src/main/java/seedu/workbook/model/internship/exceptions/InternshipNotFoundException.java b/src/main/java/seedu/workbook/model/internship/exceptions/InternshipNotFoundException.java
new file mode 100644
index 00000000000..4b03291e342
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/exceptions/InternshipNotFoundException.java
@@ -0,0 +1,6 @@
+package seedu.workbook.model.internship.exceptions;
+
+/**
+ * Signals that the operation is unable to find the specified internship.
+ */
+public class InternshipNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/workbook/model/internship/util/StageUtil.java b/src/main/java/seedu/workbook/model/internship/util/StageUtil.java
new file mode 100644
index 00000000000..74779135386
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/internship/util/StageUtil.java
@@ -0,0 +1,136 @@
+package seedu.workbook.model.internship.util;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import seedu.workbook.model.internship.Stage;
+
+/**
+ * Contains utility methods used in implementing methods regarding {@code Stage} for GUI.
+ */
+public class StageUtil {
+
+ private static final List stagesWithTips = Arrays.asList(
+ new Stage("Application Sent"),
+ new Stage("Online Assessment"),
+ new Stage("Technical Interview"),
+ new Stage("Behavioral Interview"),
+ new Stage("Phone Interview"),
+ new Stage("Rejected")
+ );
+
+ // CHECKSTYLE.OFF: LineLength
+ private static final List applicationSentTips = Arrays.asList(
+ "Contact the hiring manager/recruitment by submitting a short follow-up email to show interest in the company and stand out!",
+ "Keep a copy of your resume by the phone so that you can refer to them and answer questions if the company were to call you for a short interview!",
+ "Conduct a detailed research on the organisation you applied for, especially their mission statement, policies, initiatives and programmes to prepare for a potential interview!",
+ "Prepare for interviews and assessment by brushing up on your interview and coding skills! Refer to our tips included in “Online Assessment”, “Technical Interview” and “Behavioural Interview” for more advice!"
+ );
+
+ // 'Algorithm cheat sheets': https://www.techinterviewhandbook.org/algorithms/study-cheatsheet/
+ // 'LeetCode': https://leetcode.com/
+ private static final List onlineAssessmentTips = Arrays.asList(
+ "Decide on a programming language! We highly recommend Python as it has a huge library of useful functions and data structures!",
+ "Remember to make a note of all the important keywords in the question!",
+ "Algorithms cheat sheets - This includes the must-remembers that you should internalize for every data structure.",
+ "Keep Practicing. Not sure which questions to try? Have a look at LeetCode!"
+ );
+
+ // 'STAR': https://www.themuse.com/advice/star-interview-method
+ // 'online mock interviews': https://interviewing.io/?urc=DMCa
+ private static final List technicalInterviewTips = Arrays.asList(
+ "Do not jump into coding right away. Coding questions tend to be vague and underspecified on purpose to gauge your attention to detail and carefulness. Ask at least 2-3 clarifying questions!",
+ "Before starting, go through the different ways you could solve this question, discussing the time and space complexity tradeoffs!",
+ "Explain what you are trying to achieve as you are coding to your interviewer, so he knows exactly what you are doing at each step!",
+ "Once finished, remember to ALWAYS check that your code compiles and works for edge cases as well!"
+ );
+
+ private static final List behavioralInterviewTips = Arrays.asList(
+ "Mainly looking at your soft-skills and your ability to adapt and navigate about scenarios presented in the workplace.",
+ "Prepare relevant-to-the-role experiences beforehand, especially if it’s from school projects because you’re still a student! ;)",
+ "Try out the STAR framework to keep your answers concise and relevant to the question.",
+ "Be yourself! Be natural and confident. If it helps, practice with a friend and let them evaluate you. You can also try scheduling online mock interviews to put your skills to the test."
+ );
+
+ private static final List phoneInterviewTips = Arrays.asList(
+ "A recruiter is looking for the following indicators during the Phone Interview: Passion for tech/coding, Enthusiasm, Communication skills, Culture fit, Alignment with company mission/values",
+ "As such, focus on displaying your soft skills (Show not tell!)",
+ "Radiate excitement about the company or project, and that positivity will make a good first impression on your interviewer.",
+ "Be honest: What interests you the most about this job? What kinds of projects were you hoping to work on?",
+ "Do your research and tailor your answers to the exact position and company you’re interviewing for.",
+ "Look for opportunities to show your value alignment. Show that you support the mission of the organization."
+ );
+
+ private static final List rejectedTips = Arrays.asList(
+ "Acknowledge your emotions and feelings about the rejection. Don’t worry, it is perfectly normal to feel this way but don’t give up!",
+ "Remind yourself that you are competent. Getting rejected does not mean you are not qualified, it could just mean that there was an applicant more suitable for the particular job! Capitalise on the skills and expertise that are unique to yourself!",
+ "Express gratitude by thanking the company for the opportunity and taking the time to know you better! If you are interested in applying to the company in the future, do also maintain a good impression and let them know about it! :)",
+ "Ask for feedback from the company so that you can do better the next time! It’ll be good to find out what went well, what could be improved on and how to go about improving them!",
+ "Most importantly, keep trying and move on to the next opportunity, they are plenty awaiting you! Sharpen, refine your skills before applying for internships again, you’ll be one step closer to landing the internship of your dream!"
+ );
+ // CHECKSTYLE.ON: LineLength
+
+ private static final List> listOfTips = Arrays.asList(
+ applicationSentTips,
+ onlineAssessmentTips,
+ technicalInterviewTips,
+ behavioralInterviewTips,
+ phoneInterviewTips,
+ rejectedTips
+ );
+
+
+ private static final Map> tipsForStage = new HashMap<>();
+
+ /*
+ * Static initialization block to populate the map.
+ * Each stage is mapped to a list of tips.
+ */
+ static {
+ for (int i = 0; i < stagesWithTips.size(); i++) {
+ tipsForStage.put(stagesWithTips.get(i), listOfTips.get(i));
+ }
+ }
+
+ /**
+ * Returns the list of stages with curated tips.
+ */
+ public static List getStagesWithTips() {
+ return stagesWithTips;
+ }
+
+ /**
+ * Returns a list of tips if stage is present in {@code stagesWithTips},
+ * otherwise return an empty list.
+ * @param stage the given stage
+ * @return a list of stage-specific tips
+ */
+ public static List getStageSpecificTips(Stage stage) {
+ return (!stagesWithTips.contains(stage))
+ ? Collections.emptyList()
+ : tipsForStage.get(stage);
+ }
+
+
+ /**
+ * Checks if a stage is in the pre-defined list of stages which has tips.
+ * @param stage the given stage
+ * @return true if the stage has tips
+ */
+ public static boolean stageHasTips(Stage stage) {
+ return stagesWithTips.contains(stage);
+ }
+
+ /**
+ * Returns the list of stages with curated tips as a string
+ * for {@code CommandResult} message to hint users on
+ * the stages we have tips for.
+ */
+ public static String stagesWithTipsToString() {
+ return stagesWithTips.toString();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/workbook/model/tag/Tag.java
similarity index 65%
rename from src/main/java/seedu/address/model/tag/Tag.java
rename to src/main/java/seedu/workbook/model/tag/Tag.java
index b0ea7e7dad7..62f9c441e90 100644
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ b/src/main/java/seedu/workbook/model/tag/Tag.java
@@ -1,16 +1,14 @@
-package seedu.address.model.tag;
+package seedu.workbook.model.tag;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Tag in the address book.
- * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)}
+ * Represents a Tag in WorkBook.
+ * Guarantees: immutable; any String is taken as a valid Tag/Language Tag
*/
public class Tag {
- public static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric";
- public static final String VALIDATION_REGEX = "\\p{Alnum}+";
+ public static final String MESSAGE_CONSTRAINTS = "Tag names should not be blank";
public final String tagName;
@@ -21,7 +19,6 @@ public class Tag {
*/
public Tag(String tagName) {
requireNonNull(tagName);
- checkArgument(isValidTagName(tagName), MESSAGE_CONSTRAINTS);
this.tagName = tagName;
}
@@ -29,7 +26,7 @@ public Tag(String tagName) {
* Returns true if a given string is a valid tag name.
*/
public static boolean isValidTagName(String test) {
- return test.matches(VALIDATION_REGEX);
+ return !test.isBlank();
}
@Override
diff --git a/src/main/java/seedu/workbook/model/util/SampleDataUtil.java b/src/main/java/seedu/workbook/model/util/SampleDataUtil.java
new file mode 100644
index 00000000000..069eaa1021c
--- /dev/null
+++ b/src/main/java/seedu/workbook/model/util/SampleDataUtil.java
@@ -0,0 +1,91 @@
+package seedu.workbook.model.util;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import seedu.workbook.model.ReadOnlyWorkBook;
+import seedu.workbook.model.WorkBook;
+import seedu.workbook.model.internship.Company;
+import seedu.workbook.model.internship.DateTime;
+import seedu.workbook.model.internship.Email;
+import seedu.workbook.model.internship.Internship;
+import seedu.workbook.model.internship.Role;
+import seedu.workbook.model.internship.Stage;
+import seedu.workbook.model.tag.Tag;
+
+/**
+ * Contains utility methods for populating {@code WorkBook} with sample data.
+ */
+public class SampleDataUtil {
+ public static Internship[] getSampleInternships() {
+ return new Internship[] {
+ new Internship(
+ new Company("Jane Street"),
+ new Role("Software Engineer"),
+ new Email("hr@janestreet.com"),
+ new Stage("HR Interview"),
+ new DateTime("11-Dec-2022 15:30"),
+ getTagSet("OCaml"),
+ getTagSet("remote")),
+ new Internship(
+ new Company("Hudson River Trading"),
+ new Role("Algorithm Engineer"),
+ new Email("teamlead@hrt.com"),
+ new Stage("Interview with Team Lead"),
+ new DateTime("11-Dec-2022 18:30"),
+ getTagSet("Python"),
+ getTagSet("quant")),
+ new Internship(
+ new Company("Shopee"),
+ new Role("Android Engineer"),
+ Email.EMPTY_EMAIL,
+ new Stage("Online Assessment"),
+ new DateTime("12-Dec-2022 18:30"),
+ getTagSet("Kotlin"),
+ getTagSet("backup")),
+ new Internship(
+ new Company("Visa"),
+ new Role("Backend Engineer"),
+ Email.EMPTY_EMAIL,
+ new Stage("Technical Interview"),
+ new DateTime("15-Oct-2022 16:00"),
+ getTagSet("Java"),
+ getTagSet("payments")),
+ new Internship(
+ new Company("Binance"),
+ new Role("Blockchain Engineer"),
+ new Email("hr@binance.com"),
+ new Stage("Application Sent"),
+ DateTime.EMPTY_DATETIME,
+ getTagSet("Solidity"),
+ getTagSet("crypto")),
+ new Internship(
+ new Company("Optiver"),
+ new Role("Software Engineer"),
+ Email.EMPTY_EMAIL,
+ new Stage("Rejected"),
+ new DateTime("20-Oct-2022 10:20"),
+ getTagSet("Rust"),
+ getTagSet("trading"))
+ };
+ }
+
+ public static ReadOnlyWorkBook getSampleWorkBook() {
+ WorkBook sampleWb = new WorkBook();
+ for (Internship sampleInternship : getSampleInternships()) {
+ sampleWb.addInternship(sampleInternship);
+ }
+ return sampleWb;
+ }
+
+ /**
+ * Returns a tag set containing the list of strings given.
+ */
+ public static Set getTagSet(String... strings) {
+ return Arrays.stream(strings)
+ .map(Tag::new)
+ .collect(Collectors.toSet());
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/storage/JsonAdaptedDateTime.java b/src/main/java/seedu/workbook/storage/JsonAdaptedDateTime.java
new file mode 100644
index 00000000000..051aec4dc9f
--- /dev/null
+++ b/src/main/java/seedu/workbook/storage/JsonAdaptedDateTime.java
@@ -0,0 +1,50 @@
+/*
+package seedu.workbook.storage;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import seedu.workbook.commons.exceptions.IllegalValueException;
+import seedu.workbook.model.internship.DateTime;
+
+public class JsonAdaptedDateTime {
+
+ private final String date;
+ */
+/**
+ * Constructs a {@code JsonAdaptedDateTime} with the given {@code daye}.
+ *//*
+
+ @JsonCreator
+ public JsonAdaptedDateTime(String date) {
+ this.date = date;
+ }
+
+ */
+/**
+ * Converts a given {@code DateTime} into this class for Jackson use.
+ *//*
+
+ public JsonAdaptedDateTime(DateTime source) {
+ date = source.value;
+ }
+
+ @JsonValue
+ public String getDateTime() {
+ return date;
+ }
+
+ */
+/**
+ * Converts this Jackson-friendly adapted date object into the model's {@code DateTime} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted date.
+ *//*
+
+ public DateTime toModelType() throws IllegalValueException {
+ if (!DateTime.isValidDate(date)) {
+ throw new IllegalValueException(DateTime.MESSAGE_CONSTRAINTS);
+ }
+ return new DateTime(date);
+ }
+}
+*/
diff --git a/src/main/java/seedu/workbook/storage/JsonAdaptedInternship.java b/src/main/java/seedu/workbook/storage/JsonAdaptedInternship.java
new file mode 100644
index 00000000000..293cb2350b0
--- /dev/null
+++ b/src/main/java/seedu/workbook/storage/JsonAdaptedInternship.java
@@ -0,0 +1,143 @@
+package seedu.workbook.storage;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.workbook.commons.exceptions.IllegalValueException;
+import seedu.workbook.model.internship.Company;
+import seedu.workbook.model.internship.DateTime;
+import seedu.workbook.model.internship.Email;
+import seedu.workbook.model.internship.Internship;
+import seedu.workbook.model.internship.Role;
+import seedu.workbook.model.internship.Stage;
+import seedu.workbook.model.tag.Tag;
+
+/**
+ * Jackson-friendly version of {@link Internship}.
+ */
+class JsonAdaptedInternship {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Internship's %s field is missing!";
+
+ private final String company;
+ private final String role;
+ private final String email;
+ private final String stage;
+ private final String dateTime;
+ private final List languages = new ArrayList<>();
+ private final List tagged = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonAdaptedInternship} with the given Internship details.
+ */
+ @JsonCreator
+ public JsonAdaptedInternship(@JsonProperty("company") String company, @JsonProperty("role") String role,
+ @JsonProperty("email") String email,
+ @JsonProperty("stage") String stage,
+ @JsonProperty("dateTime") String dateTime,
+ @JsonProperty("languages") List languages,
+ @JsonProperty("tagged") List tagged) {
+ this.company = company;
+ this.role = role;
+ this.email = email;
+ this.stage = stage;
+ this.dateTime = dateTime;
+ if (languages != null) {
+ this.languages.addAll(languages);
+ }
+ if (tagged != null) {
+ this.tagged.addAll(tagged);
+ }
+ }
+
+ /**
+ * Converts a given {@code Internship} into this class for Jackson use.
+ */
+ public JsonAdaptedInternship(Internship source) {
+ company = source.getCompany().name;
+ role = source.getRole().value;
+ email = source.getEmail().value;
+ stage = source.getStage().value;
+ dateTime = source.getDateTime().value;
+ languages.addAll(source.getLanguageTags().stream()
+ .map(JsonAdaptedTag::new)
+ .collect(Collectors.toList()));
+ tagged.addAll(source.getTags().stream()
+ .map(JsonAdaptedTag::new)
+ .collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted Internship object into the model's
+ * {@code Internship} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in
+ * the adapted Internship.
+ */
+ public Internship toModelType() throws IllegalValueException {
+ final List languageTags = new ArrayList<>();
+ for (JsonAdaptedTag language : languages) {
+ languageTags.add(language.toModelType());
+ }
+
+ final List tags = new ArrayList<>();
+ for (JsonAdaptedTag tag : tagged) {
+ tags.add(tag.toModelType());
+ }
+
+ if (company == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Company.class.getSimpleName()));
+ }
+ if (!Company.isValidCompany(company)) {
+ throw new IllegalValueException(Company.MESSAGE_CONSTRAINTS);
+ }
+ final Company modelCompany = new Company(company);
+
+ if (role == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Role.class.getSimpleName()));
+ }
+ if (!Role.isValidRole(role)) {
+ throw new IllegalValueException(Role.MESSAGE_CONSTRAINTS);
+ }
+ final Role modelRole = new Role(role);
+
+ if (email == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()));
+ }
+ if (!Email.isValidEmail(email)) {
+ throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS);
+ }
+ final Email modelEmail = new Email(email);
+
+ if (stage == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Stage.class.getSimpleName()));
+ }
+ if (!Stage.isValidStage(stage)) {
+ throw new IllegalValueException(Stage.MESSAGE_CONSTRAINTS);
+ }
+ final Stage modelStage = new Stage(stage);
+
+ if (dateTime == null) {
+ throw new IllegalValueException(
+ String.format(MISSING_FIELD_MESSAGE_FORMAT, DateTime.class.getSimpleName()));
+ }
+ if (!DateTime.isValidDateTime(dateTime)) {
+ throw new IllegalValueException(DateTime.MESSAGE_CONSTRAINTS);
+ }
+ final DateTime modelDateTime = new DateTime(dateTime);
+
+ final Set modelLanguageTags = new HashSet<>(languageTags);
+
+ final Set modelTags = new HashSet<>(tags);
+
+ return new Internship(modelCompany, modelRole, modelEmail, modelStage, modelDateTime, modelLanguageTags,
+ modelTags);
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/seedu/workbook/storage/JsonAdaptedTag.java
similarity index 89%
rename from src/main/java/seedu/address/storage/JsonAdaptedTag.java
rename to src/main/java/seedu/workbook/storage/JsonAdaptedTag.java
index 0df22bdb754..09d736f9c2b 100644
--- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java
+++ b/src/main/java/seedu/workbook/storage/JsonAdaptedTag.java
@@ -1,10 +1,10 @@
-package seedu.address.storage;
+package seedu.workbook.storage;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.tag.Tag;
+import seedu.workbook.commons.exceptions.IllegalValueException;
+import seedu.workbook.model.tag.Tag;
/**
* Jackson-friendly version of {@link Tag}.
diff --git a/src/main/java/seedu/workbook/storage/JsonSerializableWorkBook.java b/src/main/java/seedu/workbook/storage/JsonSerializableWorkBook.java
new file mode 100644
index 00000000000..d93435e5901
--- /dev/null
+++ b/src/main/java/seedu/workbook/storage/JsonSerializableWorkBook.java
@@ -0,0 +1,62 @@
+package seedu.workbook.storage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+
+import seedu.workbook.commons.exceptions.IllegalValueException;
+import seedu.workbook.model.ReadOnlyWorkBook;
+import seedu.workbook.model.WorkBook;
+import seedu.workbook.model.internship.Internship;
+
+/**
+ * An Immutable WorkBook that is serializable to JSON format.
+ */
+@JsonRootName(value = "workbook")
+class JsonSerializableWorkBook {
+
+ public static final String MESSAGE_DUPLICATE_INTERNSHIP = "Internship list contains duplicate internship(s).";
+
+ private final List internships = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonSerializableWorkBook} with the given internships.
+ */
+ @JsonCreator
+ public JsonSerializableWorkBook(@JsonProperty("internships") List internships) {
+ this.internships.addAll(internships);
+ }
+
+ /**
+ * Converts a given {@code ReadOnlyWorkBook} into this class for Jackson use.
+ *
+ * @param source future changes to this will not affect the created
+ * {@code JsonSerializableWorkBook}.
+ */
+ public JsonSerializableWorkBook(ReadOnlyWorkBook source) {
+ internships.addAll(
+ source.getInternshipList().stream().map(JsonAdaptedInternship::new).collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this work book into the model's {@code WorkBook} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated.
+ */
+ public WorkBook toModelType() throws IllegalValueException {
+ WorkBook workBook = new WorkBook();
+ for (JsonAdaptedInternship jsonAdaptedInternship : internships) {
+ Internship internship = jsonAdaptedInternship.toModelType();
+ if (workBook.hasInternship(internship)) {
+ throw new IllegalValueException(MESSAGE_DUPLICATE_INTERNSHIP);
+ }
+ workBook.addInternship(internship);
+ }
+ return workBook;
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java b/src/main/java/seedu/workbook/storage/JsonUserPrefsStorage.java
similarity index 82%
rename from src/main/java/seedu/address/storage/JsonUserPrefsStorage.java
rename to src/main/java/seedu/workbook/storage/JsonUserPrefsStorage.java
index bc2bbad84aa..7a6d9f937f7 100644
--- a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java
+++ b/src/main/java/seedu/workbook/storage/JsonUserPrefsStorage.java
@@ -1,13 +1,13 @@
-package seedu.address.storage;
+package seedu.workbook.storage;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
+import seedu.workbook.commons.exceptions.DataConversionException;
+import seedu.workbook.commons.util.JsonUtil;
+import seedu.workbook.model.ReadOnlyUserPrefs;
+import seedu.workbook.model.UserPrefs;
/**
* A class to access UserPrefs stored in the hard disk as a json file
diff --git a/src/main/java/seedu/workbook/storage/JsonWorkBookStorage.java b/src/main/java/seedu/workbook/storage/JsonWorkBookStorage.java
new file mode 100644
index 00000000000..bdfe2fecdc4
--- /dev/null
+++ b/src/main/java/seedu/workbook/storage/JsonWorkBookStorage.java
@@ -0,0 +1,80 @@
+package seedu.workbook.storage;
+
+import static java.util.Objects.requireNonNull;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.commons.exceptions.DataConversionException;
+import seedu.workbook.commons.exceptions.IllegalValueException;
+import seedu.workbook.commons.util.FileUtil;
+import seedu.workbook.commons.util.JsonUtil;
+import seedu.workbook.model.ReadOnlyWorkBook;
+
+/**
+ * A class to access WorkBook data stored as a json file on the hard disk.
+ */
+public class JsonWorkBookStorage implements WorkBookStorage {
+
+ private static final Logger logger = LogsCenter.getLogger(JsonWorkBookStorage.class);
+
+ private Path filePath;
+
+ public JsonWorkBookStorage(Path filePath) {
+ this.filePath = filePath;
+ }
+
+ public Path getWorkBookFilePath() {
+ return filePath;
+ }
+
+ @Override
+ public Optional readWorkBook() throws DataConversionException {
+ return readWorkBook(filePath);
+ }
+
+ /**
+ * Similar to {@link #readWorkBook()}.
+ *
+ * @param filePath location of the data. Cannot be null.
+ * @throws DataConversionException if the file is not in the correct format.
+ */
+ public Optional readWorkBook(Path filePath) throws DataConversionException {
+ requireNonNull(filePath);
+
+ Optional jsonWorkBook = JsonUtil.readJsonFile(
+ filePath, JsonSerializableWorkBook.class);
+ if (!jsonWorkBook.isPresent()) {
+ return Optional.empty();
+ }
+
+ try {
+ return Optional.of(jsonWorkBook.get().toModelType());
+ } catch (IllegalValueException ive) {
+ logger.info("Illegal values found in " + filePath + ": " + ive.getMessage());
+ throw new DataConversionException(ive);
+ }
+ }
+
+ @Override
+ public void saveWorkBook(ReadOnlyWorkBook workBook) throws IOException {
+ saveWorkBook(workBook, filePath);
+ }
+
+ /**
+ * Similar to {@link #saveWorkBook(ReadOnlyWorkBook)}.
+ *
+ * @param filePath location of the data. Cannot be null.
+ */
+ public void saveWorkBook(ReadOnlyWorkBook workBook, Path filePath) throws IOException {
+ requireNonNull(workBook);
+ requireNonNull(filePath);
+
+ FileUtil.createIfMissing(filePath);
+ JsonUtil.saveJsonFile(new JsonSerializableWorkBook(workBook), filePath);
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/storage/Storage.java b/src/main/java/seedu/workbook/storage/Storage.java
new file mode 100644
index 00000000000..f13b2704184
--- /dev/null
+++ b/src/main/java/seedu/workbook/storage/Storage.java
@@ -0,0 +1,32 @@
+package seedu.workbook.storage;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import seedu.workbook.commons.exceptions.DataConversionException;
+import seedu.workbook.model.ReadOnlyUserPrefs;
+import seedu.workbook.model.ReadOnlyWorkBook;
+import seedu.workbook.model.UserPrefs;
+
+/**
+ * API of the Storage component
+ */
+public interface Storage extends WorkBookStorage, UserPrefsStorage {
+
+ @Override
+ Optional readUserPrefs() throws DataConversionException, IOException;
+
+ @Override
+ void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException;
+
+ @Override
+ Path getWorkBookFilePath();
+
+ @Override
+ Optional readWorkBook() throws DataConversionException, IOException;
+
+ @Override
+ void saveWorkBook(ReadOnlyWorkBook workBook) throws IOException;
+
+}
diff --git a/src/main/java/seedu/workbook/storage/StorageManager.java b/src/main/java/seedu/workbook/storage/StorageManager.java
new file mode 100644
index 00000000000..90a20eea00c
--- /dev/null
+++ b/src/main/java/seedu/workbook/storage/StorageManager.java
@@ -0,0 +1,78 @@
+package seedu.workbook.storage;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.commons.exceptions.DataConversionException;
+import seedu.workbook.model.ReadOnlyUserPrefs;
+import seedu.workbook.model.ReadOnlyWorkBook;
+import seedu.workbook.model.UserPrefs;
+
+/**
+ * Manages storage of WorkBook data in local storage.
+ */
+public class StorageManager implements Storage {
+
+ private static final Logger logger = LogsCenter.getLogger(StorageManager.class);
+ private WorkBookStorage workBookStorage;
+ private UserPrefsStorage userPrefsStorage;
+
+ /**
+ * Creates a {@code StorageManager} with the given {@code WorkBookStorage} and {@code UserPrefStorage}.
+ */
+ public StorageManager(WorkBookStorage workBookStorage, UserPrefsStorage userPrefsStorage) {
+ this.workBookStorage = workBookStorage;
+ this.userPrefsStorage = userPrefsStorage;
+ }
+
+ // ================ UserPrefs methods ==============================
+
+ @Override
+ public Path getUserPrefsFilePath() {
+ return userPrefsStorage.getUserPrefsFilePath();
+ }
+
+ @Override
+ public Optional readUserPrefs() throws DataConversionException, IOException {
+ return userPrefsStorage.readUserPrefs();
+ }
+
+ @Override
+ public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException {
+ userPrefsStorage.saveUserPrefs(userPrefs);
+ }
+
+
+ // ================ WorkBook methods ==============================
+
+ @Override
+ public Path getWorkBookFilePath() {
+ return workBookStorage.getWorkBookFilePath();
+ }
+
+ @Override
+ public Optional readWorkBook() throws DataConversionException, IOException {
+ return readWorkBook(workBookStorage.getWorkBookFilePath());
+ }
+
+ @Override
+ public Optional readWorkBook(Path filePath) throws DataConversionException, IOException {
+ logger.fine("Attempting to read data from file: " + filePath);
+ return workBookStorage.readWorkBook(filePath);
+ }
+
+ @Override
+ public void saveWorkBook(ReadOnlyWorkBook workBook) throws IOException {
+ saveWorkBook(workBook, workBookStorage.getWorkBookFilePath());
+ }
+
+ @Override
+ public void saveWorkBook(ReadOnlyWorkBook workBook, Path filePath) throws IOException {
+ logger.fine("Attempting to write to data file: " + filePath);
+ workBookStorage.saveWorkBook(workBook, filePath);
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/UserPrefsStorage.java b/src/main/java/seedu/workbook/storage/UserPrefsStorage.java
similarity index 71%
rename from src/main/java/seedu/address/storage/UserPrefsStorage.java
rename to src/main/java/seedu/workbook/storage/UserPrefsStorage.java
index 29eef178dbc..f70b18c4b8a 100644
--- a/src/main/java/seedu/address/storage/UserPrefsStorage.java
+++ b/src/main/java/seedu/workbook/storage/UserPrefsStorage.java
@@ -1,15 +1,15 @@
-package seedu.address.storage;
+package seedu.workbook.storage;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
+import seedu.workbook.commons.exceptions.DataConversionException;
+import seedu.workbook.model.ReadOnlyUserPrefs;
+import seedu.workbook.model.UserPrefs;
/**
- * Represents a storage for {@link seedu.address.model.UserPrefs}.
+ * Represents a storage for {@link seedu.workbook.model.UserPrefs}.
*/
public interface UserPrefsStorage {
@@ -27,7 +27,7 @@ public interface UserPrefsStorage {
Optional readUserPrefs() throws DataConversionException, IOException;
/**
- * Saves the given {@link seedu.address.model.ReadOnlyUserPrefs} to the storage.
+ * Saves the given {@link seedu.workbook.model.ReadOnlyUserPrefs} to the storage.
* @param userPrefs cannot be null.
* @throws IOException if there was any problem writing to the file.
*/
diff --git a/src/main/java/seedu/workbook/storage/WorkBookStorage.java b/src/main/java/seedu/workbook/storage/WorkBookStorage.java
new file mode 100644
index 00000000000..8f890686d84
--- /dev/null
+++ b/src/main/java/seedu/workbook/storage/WorkBookStorage.java
@@ -0,0 +1,45 @@
+package seedu.workbook.storage;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import seedu.workbook.commons.exceptions.DataConversionException;
+import seedu.workbook.model.ReadOnlyWorkBook;
+
+/**
+ * Represents a storage for {@link seedu.workbook.model.WorkBook}.
+ */
+public interface WorkBookStorage {
+
+ /**
+ * Returns the file path of the data file.
+ */
+ Path getWorkBookFilePath();
+
+ /**
+ * Returns WorkBook data as a {@link ReadOnlyWorkBook}.
+ * Returns {@code Optional.empty()} if storage file is not found.
+ * @throws DataConversionException if the data in storage is not in the expected format.
+ * @throws IOException if there was any problem when reading from the storage.
+ */
+ Optional readWorkBook() throws DataConversionException, IOException;
+
+ /**
+ * @see #getWorkBookFilePath()
+ */
+ Optional readWorkBook(Path filePath) throws DataConversionException, IOException;
+
+ /**
+ * Saves the given {@link ReadOnlyWorkBook} to the storage.
+ * @param workBook cannot be null.
+ * @throws IOException if there was any problem writing to the file.
+ */
+ void saveWorkBook(ReadOnlyWorkBook workBook) throws IOException;
+
+ /**
+ * @see #saveWorkBook(ReadOnlyWorkBook)
+ */
+ void saveWorkBook(ReadOnlyWorkBook workBook, Path filePath) throws IOException;
+
+}
diff --git a/src/main/java/seedu/address/ui/CommandBox.java b/src/main/java/seedu/workbook/ui/CommandBox.java
similarity index 89%
rename from src/main/java/seedu/address/ui/CommandBox.java
rename to src/main/java/seedu/workbook/ui/CommandBox.java
index 9e75478664b..cdc8b2767d6 100644
--- a/src/main/java/seedu/address/ui/CommandBox.java
+++ b/src/main/java/seedu/workbook/ui/CommandBox.java
@@ -1,12 +1,12 @@
-package seedu.address.ui;
+package seedu.workbook.ui;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
import javafx.scene.layout.Region;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.workbook.logic.commands.CommandResult;
+import seedu.workbook.logic.commands.exceptions.CommandException;
+import seedu.workbook.logic.parser.exceptions.ParseException;
/**
* The UI component that is responsible for receiving user command inputs.
@@ -77,7 +77,7 @@ public interface CommandExecutor {
/**
* Executes the command and returns the result.
*
- * @see seedu.address.logic.Logic#execute(String)
+ * @see seedu.workbook.logic.Logic#execute(String)
*/
CommandResult execute(String commandText) throws CommandException, ParseException;
}
diff --git a/src/main/java/seedu/workbook/ui/HelpCard.java b/src/main/java/seedu/workbook/ui/HelpCard.java
new file mode 100644
index 00000000000..69fc389fcc3
--- /dev/null
+++ b/src/main/java/seedu/workbook/ui/HelpCard.java
@@ -0,0 +1,47 @@
+package seedu.workbook.ui;
+
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.Region;
+import seedu.workbook.ui.util.HelpUtil;
+import seedu.workbook.ui.util.HelpUtil.Command;
+
+/**
+ * An UI component that displays information of a {@code Internship}.
+ */
+public class HelpCard extends UiPart {
+
+ private static final String FXML = "HelpCard.fxml";
+
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ public final Command command;
+
+ @FXML
+ private Label commandLabel;
+ @FXML
+ private Label exampleLabel;
+
+
+
+
+ /**
+ * Creates a {@code HelpCard} with the given {@code Command} and example to display.
+ */
+ public HelpCard(Command command) {
+ super(FXML);
+ this.command = command;
+
+ commandLabel.setText(HelpUtil.getCommandHeader(command));
+ exampleLabel.setText(HelpUtil.getCommandExample(command));
+ }
+
+}
diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/workbook/ui/HelpWindow.java
similarity index 77%
rename from src/main/java/seedu/address/ui/HelpWindow.java
rename to src/main/java/seedu/workbook/ui/HelpWindow.java
index 3f16b2fcf26..2c2f5017304 100644
--- a/src/main/java/seedu/address/ui/HelpWindow.java
+++ b/src/main/java/seedu/workbook/ui/HelpWindow.java
@@ -1,31 +1,27 @@
-package seedu.address.ui;
+package seedu.workbook.ui;
import java.util.logging.Logger;
import javafx.fxml.FXML;
-import javafx.scene.control.Button;
-import javafx.scene.control.Label;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
+import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
-import seedu.address.commons.core.LogsCenter;
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.ui.util.HelpUtil;
+import seedu.workbook.ui.util.HelpUtil.Command;
/**
* Controller for a help page
*/
public class HelpWindow extends UiPart {
- public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html";
- public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL;
private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
private static final String FXML = "HelpWindow.fxml";
@FXML
- private Button copyButton;
-
- @FXML
- private Label helpMessage;
+ private GridPane gridPane;
/**
* Creates a new HelpWindow.
@@ -34,7 +30,16 @@ public class HelpWindow extends UiPart {
*/
public HelpWindow(Stage root) {
super(FXML, root);
- helpMessage.setText(HELP_MESSAGE);
+
+ for (int i = 0; i < Command.values().length; i++) {
+ Command command = Command.values()[i];
+ HelpCard helpCard = new HelpCard(command);
+ gridPane.add(helpCard.getRoot(), 0, i + 1);
+ }
+
+ UrlCard urlCard = new UrlCard();
+ gridPane.add(urlCard.getRoot(), 0, Command.values().length + 1);
+
}
/**
@@ -96,7 +101,7 @@ public void focus() {
private void copyUrl() {
final Clipboard clipboard = Clipboard.getSystemClipboard();
final ClipboardContent url = new ClipboardContent();
- url.putString(USERGUIDE_URL);
+ url.putString(HelpUtil.getUserGuideUrl());
clipboard.setContent(url);
}
}
diff --git a/src/main/java/seedu/workbook/ui/InternshipCard.java b/src/main/java/seedu/workbook/ui/InternshipCard.java
new file mode 100644
index 00000000000..23e0577fd06
--- /dev/null
+++ b/src/main/java/seedu/workbook/ui/InternshipCard.java
@@ -0,0 +1,130 @@
+package seedu.workbook.ui;
+
+
+import java.util.Comparator;
+import java.util.List;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import seedu.workbook.model.internship.Internship;
+import seedu.workbook.model.internship.Stage;
+import seedu.workbook.model.internship.util.StageUtil;
+
+/**
+ * An UI component that displays information of a {@code Internship}.
+ */
+public class InternshipCard extends UiPart {
+
+ private static final String FXML = "InternshipListCard.fxml";
+
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ public final Internship internship;
+
+ //Independent tips window residing in each internship list card controller
+ private TipsWindow tipsWindow;
+
+ private final Stage internshipStage;
+
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private Label company;
+ @FXML
+ private Label role;
+ @FXML
+ private Label id;
+ @FXML
+ private Label email;
+ @FXML
+ private Label stage;
+ @FXML
+ private Label dateTime;
+ @FXML
+ private FlowPane tags;
+ @FXML
+ private Button tipsButton;
+
+
+ /**
+ * Creates a {@code InternshipCode} with the given {@code Internship} and index to display.
+ */
+ public InternshipCard(Internship internship, int displayedIndex) {
+ super(FXML);
+ this.internship = internship;
+ this.internshipStage = internship.getStage();
+ boolean hasNoTips = internshipStage.hasNoTips();
+
+ if (hasNoTips) {
+ tipsButton.setVisible(false);
+ }
+
+ id.setText(displayedIndex + ". ");
+ company.setText(internship.getCompany().name);
+ role.setText(internship.getRole().value);
+ email.setText(internship.getEmail().value);
+ stage.setText(internshipStage.value);
+ dateTime.setText(internship.getDateTime().value);
+ internship.getLanguageTags().stream()
+ .sorted(Comparator.comparing(languageTag -> languageTag.tagName))
+ .forEach(languageTag -> tags.getChildren().add(new LanguageTagLabel(languageTag.tagName)));
+ internship.getTags().stream()
+ .sorted(Comparator.comparing(tag -> tag.tagName))
+ .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+
+ tipsWindow = new TipsWindow();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof InternshipCard)) {
+ return false;
+ }
+
+ // state check
+ InternshipCard card = (InternshipCard) other;
+ return id.getText().equals(card.id.getText())
+ && internship.equals(card.internship);
+ }
+
+ /**
+ * Opens the tip window depending on the internship stage.
+ */
+ @FXML
+ private void showTips() {
+ //Check if tips window is showing.
+ if (!tipsWindow.isShowing()) {
+ //Do not populate tips window for stages that have no stage-specific tips.
+ if (this.internshipStage.hasNoTips()) {
+ return;
+ }
+
+ //Set header of tips to be name of stage.
+ tipsWindow.setTipsHeader(this.internshipStage.value);
+
+ List tips = StageUtil.getStageSpecificTips(this.internshipStage);
+
+ tipsWindow.populateTips(tips);
+ tipsWindow.show();
+ } else {
+ tipsWindow.focus();
+ }
+ }
+}
diff --git a/src/main/java/seedu/workbook/ui/InternshipListPanel.java b/src/main/java/seedu/workbook/ui/InternshipListPanel.java
new file mode 100644
index 00000000000..da0795765f8
--- /dev/null
+++ b/src/main/java/seedu/workbook/ui/InternshipListPanel.java
@@ -0,0 +1,52 @@
+package seedu.workbook.ui;
+
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.Region;
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.model.internship.Internship;
+
+/**
+ * Panel containing the list of internships.
+ */
+public class InternshipListPanel extends UiPart {
+ private static final String FXML = "InternshipListPanel.fxml";
+ private final Logger logger = LogsCenter.getLogger(InternshipListPanel.class);
+
+ @FXML
+ private ListView internshipListView;
+
+ /**
+ * Creates a {@code InternshipListPanel} with the given {@code ObservableList}.
+ */
+ public InternshipListPanel(ObservableList internshipList) {
+ super(FXML);
+ internshipListView.setItems(internshipList);
+ internshipListView.setCellFactory(listView -> new InternshipListViewCell());
+
+ // put first card into focus
+ internshipListView.getSelectionModel().selectFirst();
+ }
+
+ /**
+ * Custom {@code ListCell} that displays the graphics of a {@code Internship} using a {@code InternshipCard}.
+ */
+ class InternshipListViewCell extends ListCell {
+ @Override
+ protected void updateItem(Internship internship, boolean empty) {
+ super.updateItem(internship, empty);
+
+ if (empty || internship == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new InternshipCard(internship, getIndex() + 1).getRoot());
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/ui/LanguageTagLabel.java b/src/main/java/seedu/workbook/ui/LanguageTagLabel.java
new file mode 100644
index 00000000000..9f621fc287a
--- /dev/null
+++ b/src/main/java/seedu/workbook/ui/LanguageTagLabel.java
@@ -0,0 +1,17 @@
+package seedu.workbook.ui;
+
+import javafx.scene.control.Label;
+
+/**
+ * Custom wrapper on a JavaFX Label to allow custom css styling.
+ */
+public class LanguageTagLabel extends Label {
+ /**
+ * Creates a {@code LanguageTabLabel} with the input text.
+ */
+ public LanguageTagLabel(String text) {
+ super(text);
+ getStyleClass().setAll("languageTagLabel");
+ }
+
+}
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/workbook/ui/MainWindow.java
similarity index 74%
rename from src/main/java/seedu/address/ui/MainWindow.java
rename to src/main/java/seedu/workbook/ui/MainWindow.java
index 9106c3aa6e5..8e9f762c59c 100644
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ b/src/main/java/seedu/workbook/ui/MainWindow.java
@@ -1,4 +1,4 @@
-package seedu.address.ui;
+package seedu.workbook.ui;
import java.util.logging.Logger;
@@ -10,12 +10,12 @@
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.logic.Logic;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.workbook.commons.core.GuiSettings;
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.logic.Logic;
+import seedu.workbook.logic.commands.CommandResult;
+import seedu.workbook.logic.commands.exceptions.CommandException;
+import seedu.workbook.logic.parser.exceptions.ParseException;
/**
* The Main Window. Provides the basic application layout containing
@@ -24,6 +24,7 @@
public class MainWindow extends UiPart {
private static final String FXML = "MainWindow.fxml";
+ private static final int WIDTH_BREAKPOINT = 1000;
private final Logger logger = LogsCenter.getLogger(getClass());
@@ -31,7 +32,8 @@ public class MainWindow extends UiPart {
private Logic logic;
// Independent Ui parts residing in this Ui container
- private PersonListPanel personListPanel;
+ private InternshipListPanel internshipListPanel;
+ private WideInternshipListPanel wideInternshipListPanel;
private ResultDisplay resultDisplay;
private HelpWindow helpWindow;
@@ -42,7 +44,7 @@ public class MainWindow extends UiPart {
private MenuItem helpMenuItem;
@FXML
- private StackPane personListPanelPlaceholder;
+ private StackPane internshipListPanelPlaceholder;
@FXML
private StackPane resultDisplayPlaceholder;
@@ -65,6 +67,8 @@ public MainWindow(Stage primaryStage, Logic logic) {
setAccelerators();
+ setWidthEventHandlers();
+
helpWindow = new HelpWindow();
}
@@ -110,13 +114,18 @@ private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) {
* Fills up all the placeholders of this window.
*/
void fillInnerParts() {
- personListPanel = new PersonListPanel(logic.getFilteredPersonList());
- personListPanelPlaceholder.getChildren().add(personListPanel.getRoot());
+ internshipListPanel = new InternshipListPanel(logic.getFilteredInternshipList());
+ wideInternshipListPanel = new WideInternshipListPanel(logic.getFilteredInternshipList());
+ if (logic.getGuiSettings().getWindowWidth() >= WIDTH_BREAKPOINT) {
+ internshipListPanelPlaceholder.getChildren().add(wideInternshipListPanel.getRoot());
+ } else {
+ internshipListPanelPlaceholder.getChildren().add(internshipListPanel.getRoot());
+ }
resultDisplay = new ResultDisplay();
resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot());
- StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getAddressBookFilePath());
+ StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getWorkBookFilePath());
statusbarPlaceholder.getChildren().add(statusBarFooter.getRoot());
CommandBox commandBox = new CommandBox(this::executeCommand);
@@ -135,6 +144,19 @@ private void setWindowDefaultSize(GuiSettings guiSettings) {
}
}
+ private void setWidthEventHandlers() {
+ this.primaryStage.widthProperty().addListener((observable, oldVal, newVal) -> {
+ if (newVal.doubleValue() >= WIDTH_BREAKPOINT) {
+ // toggle to different layout
+ internshipListPanelPlaceholder.getChildren().clear();
+ internshipListPanelPlaceholder.getChildren().add(wideInternshipListPanel.getRoot());
+ } else {
+ internshipListPanelPlaceholder.getChildren().clear();
+ internshipListPanelPlaceholder.getChildren().add(internshipListPanel.getRoot());
+ }
+ });
+ }
+
/**
* Opens the help window or focuses on it if it's already opened.
*/
@@ -163,14 +185,14 @@ private void handleExit() {
primaryStage.hide();
}
- public PersonListPanel getPersonListPanel() {
- return personListPanel;
+ public InternshipListPanel getInternshipListPanel() {
+ return internshipListPanel;
}
/**
* Executes the command and returns the result.
*
- * @see seedu.address.logic.Logic#execute(String)
+ * @see seedu.workbook.logic.Logic#execute(String)
*/
private CommandResult executeCommand(String commandText) throws CommandException, ParseException {
try {
diff --git a/src/main/java/seedu/workbook/ui/NarrowInternshipCard.java b/src/main/java/seedu/workbook/ui/NarrowInternshipCard.java
new file mode 100644
index 00000000000..6595c8638e5
--- /dev/null
+++ b/src/main/java/seedu/workbook/ui/NarrowInternshipCard.java
@@ -0,0 +1,94 @@
+package seedu.workbook.ui;
+
+
+import java.util.Comparator;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import seedu.workbook.model.internship.Internship;
+
+/**
+ * An UI component that displays information of a {@code Internship}.
+ */
+public class NarrowInternshipCard extends UiPart {
+
+ private static final String FXML = "NarrowInternshipListCard.fxml";
+
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ public final Internship internship;
+
+
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private Label company;
+ @FXML
+ private Label role;
+ @FXML
+ private Label id;
+ @FXML
+ private Label email;
+ @FXML
+ private Label stage;
+ @FXML
+ private Label dateTime;
+ @FXML
+ private FlowPane tags;
+ @FXML
+ private Button tipsButton;
+
+
+ /**
+ * Creates a {@code InternshipCode} with the given {@code Internship} and index to display.
+ */
+ public NarrowInternshipCard(Internship internship, int displayedIndex) {
+ super(FXML);
+ this.internship = internship;
+
+
+ id.setText(displayedIndex + ". ");
+ company.setText(internship.getCompany().name);
+ role.setText(internship.getRole().value);
+ email.setText(internship.getEmail().value);
+ stage.setText(internship.getStage().value);
+ dateTime.setText(internship.getDateTime().value);
+ internship.getLanguageTags().stream()
+ .sorted(Comparator.comparing(languageTag -> languageTag.tagName))
+ .forEach(languageTag -> tags.getChildren().add(new LanguageTagLabel(languageTag.tagName)));
+ internship.getTags().stream()
+ .sorted(Comparator.comparing(tag -> tag.tagName))
+ .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof NarrowInternshipCard)) {
+ return false;
+ }
+
+ // state check
+ NarrowInternshipCard card = (NarrowInternshipCard) other;
+ return id.getText().equals(card.id.getText())
+ && internship.equals(card.internship);
+ }
+
+}
diff --git a/src/main/java/seedu/address/ui/ResultDisplay.java b/src/main/java/seedu/workbook/ui/ResultDisplay.java
similarity index 95%
rename from src/main/java/seedu/address/ui/ResultDisplay.java
rename to src/main/java/seedu/workbook/ui/ResultDisplay.java
index 7d98e84eedf..eb1bb89307f 100644
--- a/src/main/java/seedu/address/ui/ResultDisplay.java
+++ b/src/main/java/seedu/workbook/ui/ResultDisplay.java
@@ -1,4 +1,4 @@
-package seedu.address.ui;
+package seedu.workbook.ui;
import static java.util.Objects.requireNonNull;
diff --git a/src/main/java/seedu/address/ui/StatusBarFooter.java b/src/main/java/seedu/workbook/ui/StatusBarFooter.java
similarity index 96%
rename from src/main/java/seedu/address/ui/StatusBarFooter.java
rename to src/main/java/seedu/workbook/ui/StatusBarFooter.java
index b577f829423..4364b876d1d 100644
--- a/src/main/java/seedu/address/ui/StatusBarFooter.java
+++ b/src/main/java/seedu/workbook/ui/StatusBarFooter.java
@@ -1,4 +1,4 @@
-package seedu.address.ui;
+package seedu.workbook.ui;
import java.nio.file.Path;
import java.nio.file.Paths;
diff --git a/src/main/java/seedu/workbook/ui/TipCard.java b/src/main/java/seedu/workbook/ui/TipCard.java
new file mode 100644
index 00000000000..1a1a4f3ccb3
--- /dev/null
+++ b/src/main/java/seedu/workbook/ui/TipCard.java
@@ -0,0 +1,47 @@
+package seedu.workbook.ui;
+
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.Region;
+
+/**
+ * An UI component that displays information of a {@code Internship}.
+ */
+public class TipCard extends UiPart {
+
+ private static final String FXML = "TipCard.fxml";
+
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ public final int index;
+ public final String tip;
+
+ @FXML
+ private Label indexLabel;
+ @FXML
+ private Label tipLabel;
+
+
+
+
+ /**
+ * Creates a {@code TipCard} with the given {@code Tip} and index to display.
+ */
+ public TipCard(int index, String tip) {
+ super(FXML);
+ this.tip = tip;
+ this.index = index;
+
+ this.indexLabel.setText(String.valueOf(this.index) + ". ");
+ this.tipLabel.setText(this.tip);
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/ui/TipsPanel.java b/src/main/java/seedu/workbook/ui/TipsPanel.java
new file mode 100644
index 00000000000..535bbde692b
--- /dev/null
+++ b/src/main/java/seedu/workbook/ui/TipsPanel.java
@@ -0,0 +1,54 @@
+package seedu.workbook.ui;
+
+import java.util.List;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.Region;
+
+/**
+ * Controller for a tips panel
+ */
+public class TipsPanel extends UiPart {
+
+ private static final String FXML = "TipsPanel.fxml";
+
+ @FXML
+ private Label tipsHeader;
+
+ @FXML
+ private GridPane gridPane;
+
+
+ /**
+ * Creates a new TipsWindow.
+ */
+ public TipsPanel() {
+ super(FXML);
+ }
+
+ /*
+ * Set the tips window header to be the stage name.
+ */
+ public void setTipsHeader(String stageName) {
+ tipsHeader.setText("Tips for " + stageName);
+ }
+
+ /**
+ * Populates the tips window with tips.
+ * @param tips List of tips to populate the tip window.
+ */
+ public void populateTips(List tips) {
+ //Clear no tips label
+ gridPane.getChildren().clear();
+
+ for (int i = 0; i < tips.size(); i++) {
+ int index = i + 1;
+ String tip = tips.get(i);
+ TipCard tipCard = new TipCard(index, tip);
+ gridPane.add(tipCard.getRoot(), 0, i, 1, 1);
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/ui/TipsWindow.java b/src/main/java/seedu/workbook/ui/TipsWindow.java
new file mode 100644
index 00000000000..4d49a4e120b
--- /dev/null
+++ b/src/main/java/seedu/workbook/ui/TipsWindow.java
@@ -0,0 +1,108 @@
+package seedu.workbook.ui;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.GridPane;
+import javafx.stage.Stage;
+import seedu.workbook.commons.core.LogsCenter;
+
+/**
+ * Controller for a tips page
+ */
+public class TipsWindow extends UiPart {
+
+ private static final Logger logger = LogsCenter.getLogger(TipsWindow.class);
+ private static final String FXML = "TipsWindow.fxml";
+
+ @FXML
+ private Label tipsHeader;
+
+ @FXML
+ private GridPane gridPane;
+
+ /**
+ * Creates a new TipsWindow.
+ *
+ * @param root Stage to use as the root of the TipsWindow.
+ */
+ public TipsWindow(Stage root) {
+ super(FXML, root);
+ }
+
+ /**
+ * Creates a new TipsWindow.
+ */
+ public TipsWindow() {
+ this(new Stage());
+ }
+
+ /**
+ * Shows the help window.
+ * @throws IllegalStateException
+ *
+ *
+ * if this method is called on a thread other than the JavaFX Application Thread.
+ *
+ *
+ * if this method is called during animation or layout processing.
+ *
+ *
+ * if this method is called on the primary stage.
+ *
+ *
+ * if {@code dialogStage} is already showing.
+ *
+ *
+ */
+ public void show() {
+ logger.fine("Showing tips page about the internship stage.");
+ getRoot().show();
+ getRoot().centerOnScreen();
+ }
+
+ /**
+ * Returns true if the tips window is currently being shown.
+ */
+ public boolean isShowing() {
+ return getRoot().isShowing();
+ }
+
+ /**
+ * Hides the tips window.
+ */
+ public void hide() {
+ getRoot().hide();
+ }
+
+ /**
+ * Focuses on the tips window.
+ */
+ public void focus() {
+ getRoot().requestFocus();
+ }
+
+ /*
+ * Set the tips window header to be the stage name.
+ */
+ public void setTipsHeader(String stageName) {
+ tipsHeader.setText("Tips for " + stageName);
+ }
+
+ /**
+ * Populates the tips window with tips.
+ * @param tips List of tips to populate the tip window.
+ */
+ public void populateTips(List tips) {
+ for (int i = 0; i < tips.size(); i++) {
+
+ int index = i + 1;
+ String tip = tips.get(i);
+ TipCard tipCard = new TipCard(index, tip);
+ gridPane.add(tipCard.getRoot(), 0, i, 1, 1);
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/address/ui/Ui.java b/src/main/java/seedu/workbook/ui/Ui.java
similarity index 85%
rename from src/main/java/seedu/address/ui/Ui.java
rename to src/main/java/seedu/workbook/ui/Ui.java
index 17aa0b494fe..a254067b93c 100644
--- a/src/main/java/seedu/address/ui/Ui.java
+++ b/src/main/java/seedu/workbook/ui/Ui.java
@@ -1,4 +1,4 @@
-package seedu.address.ui;
+package seedu.workbook.ui;
import javafx.stage.Stage;
diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/seedu/workbook/ui/UiManager.java
similarity index 93%
rename from src/main/java/seedu/address/ui/UiManager.java
rename to src/main/java/seedu/workbook/ui/UiManager.java
index fdf024138bc..64f16062457 100644
--- a/src/main/java/seedu/address/ui/UiManager.java
+++ b/src/main/java/seedu/workbook/ui/UiManager.java
@@ -1,4 +1,4 @@
-package seedu.address.ui;
+package seedu.workbook.ui;
import java.util.logging.Logger;
@@ -7,10 +7,10 @@
import javafx.scene.control.Alert.AlertType;
import javafx.scene.image.Image;
import javafx.stage.Stage;
-import seedu.address.MainApp;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.logic.Logic;
+import seedu.workbook.MainApp;
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.commons.util.StringUtil;
+import seedu.workbook.logic.Logic;
/**
* The manager of the UI component.
diff --git a/src/main/java/seedu/address/ui/UiPart.java b/src/main/java/seedu/workbook/ui/UiPart.java
similarity index 97%
rename from src/main/java/seedu/address/ui/UiPart.java
rename to src/main/java/seedu/workbook/ui/UiPart.java
index fc820e01a9c..6d7e3603357 100644
--- a/src/main/java/seedu/address/ui/UiPart.java
+++ b/src/main/java/seedu/workbook/ui/UiPart.java
@@ -1,4 +1,4 @@
-package seedu.address.ui;
+package seedu.workbook.ui;
import static java.util.Objects.requireNonNull;
@@ -6,7 +6,7 @@
import java.net.URL;
import javafx.fxml.FXMLLoader;
-import seedu.address.MainApp;
+import seedu.workbook.MainApp;
/**
* Represents a distinct part of the UI. e.g. Windows, dialogs, panels, status bars, etc.
diff --git a/src/main/java/seedu/workbook/ui/UrlCard.java b/src/main/java/seedu/workbook/ui/UrlCard.java
new file mode 100644
index 00000000000..95989a3889d
--- /dev/null
+++ b/src/main/java/seedu/workbook/ui/UrlCard.java
@@ -0,0 +1,55 @@
+package seedu.workbook.ui;
+
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.input.Clipboard;
+import javafx.scene.input.ClipboardContent;
+import javafx.scene.layout.Region;
+import seedu.workbook.ui.util.HelpUtil;
+
+/**
+ * An UI component that displays the {@code URL} of the {@code User Guide}.
+ */
+public class UrlCard extends UiPart {
+
+ private static final String FXML = "UrlCard.fxml";
+
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ @FXML
+ private Label urlMessage;
+
+ @FXML
+ private Button copyButton;
+
+
+ /**
+ * Creates a {@code URLCard} with the given {@code URL} and message to display.
+ */
+ public UrlCard() {
+ super(FXML);
+
+ urlMessage.setText(HelpUtil.getUrlMessage());
+ }
+
+ /**
+ * Copies the URL to the user guide to the clipboard.
+ */
+ @FXML
+ private void copyUrl() {
+ final Clipboard clipboard = Clipboard.getSystemClipboard();
+ final ClipboardContent url = new ClipboardContent();
+ url.putString(HelpUtil.getUserGuideUrl());
+ clipboard.setContent(url);
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/ui/WideInternshipListPanel.java b/src/main/java/seedu/workbook/ui/WideInternshipListPanel.java
new file mode 100644
index 00000000000..648134c94c0
--- /dev/null
+++ b/src/main/java/seedu/workbook/ui/WideInternshipListPanel.java
@@ -0,0 +1,102 @@
+package seedu.workbook.ui;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import seedu.workbook.commons.core.LogsCenter;
+import seedu.workbook.model.internship.Internship;
+import seedu.workbook.model.internship.Stage;
+import seedu.workbook.model.internship.util.StageUtil;
+
+/**
+ * Panel containing the list of internships for wide window format.
+ */
+public class WideInternshipListPanel extends UiPart {
+ private static final String FXML = "WideInternshipListPanel.fxml";
+ private final Logger logger = LogsCenter.getLogger(WideInternshipListPanel.class);
+
+ @FXML
+ private HBox tipsPanelContainer;
+
+ @FXML
+ private ListView wideInternshipListView;
+
+ /**
+ * Creates a {@code WideInternshipListPanel} with the given {@code ObservableList}.
+ */
+ public WideInternshipListPanel(ObservableList internshipList) {
+ super(FXML);
+ wideInternshipListView.setItems(internshipList);
+ wideInternshipListView.setCellFactory(listView -> new WideInternshipListViewCell());
+ setInternshipSelectedEventHandlers();
+
+ // put first card into focus
+ wideInternshipListView.getSelectionModel().selectFirst();
+ }
+
+ /**
+ * Custom {@code ListCell} that displays the graphics of a {@code Internship} using a {@code InternshipCard}.
+ */
+ class WideInternshipListViewCell extends ListCell {
+ @Override
+ protected void updateItem(Internship internship, boolean empty) {
+ super.updateItem(internship, empty);
+
+ if (empty || internship == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new NarrowInternshipCard(internship, getIndex() + 1).getRoot());
+ }
+ }
+ }
+
+ /**
+ * Add listener to when an internship card is selected.
+ */
+ private void setInternshipSelectedEventHandlers() {
+ this.wideInternshipListView
+ .getSelectionModel()
+ .selectedItemProperty()
+ .addListener((observable, oldVal, newVal) -> {
+ tipsPanelContainer.getChildren().clear();
+ // should not show tips when no card is selected
+ if (newVal == null) {
+ return;
+ }
+ TipsPanel tipsPanel = tipPanelBuilder(newVal.getStage());
+ tipsPanelContainer.getChildren().add(tipsPanel.getRoot());
+ });
+ }
+
+ /**
+ * Builds a {@code TipsPanel} from the given internship {@code internshipStage}.
+ * @param internshipStage
+ * @return
+ */
+ private TipsPanel tipPanelBuilder(Stage internshipStage) {
+
+ TipsPanel tipsPanel = new TipsPanel();
+
+ //Set header of tips to be name of stage.
+ tipsPanel.setTipsHeader(internshipStage.value);
+
+ if (internshipStage.hasNoTips()) {
+ //Default tips panel has no tips label
+ return tipsPanel;
+ }
+
+ List tips = StageUtil.getStageSpecificTips(internshipStage);
+
+ tipsPanel.populateTips(tips);
+
+ return tipsPanel;
+ }
+
+}
diff --git a/src/main/java/seedu/workbook/ui/util/HelpUtil.java b/src/main/java/seedu/workbook/ui/util/HelpUtil.java
new file mode 100644
index 00000000000..2bc35d083e8
--- /dev/null
+++ b/src/main/java/seedu/workbook/ui/util/HelpUtil.java
@@ -0,0 +1,107 @@
+package seedu.workbook.ui.util;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Contains utility methods used in implementing methods regarding {@code HelpWindow} for GUI.
+ */
+public class HelpUtil {
+
+ public static final String ADD_HEADER = "Add an Internship: ";
+ public static final String ADD_EXAMPLE = "add c/COMPANY r/ROLE s/STAGE [d/DATETIME] [e/EMAIL] "
+ + "[l/PROGRAMMING LANGUAGE]… [t/TAG]…";
+ public static final String EDIT_HEADER = "Edit an Internship: ";
+ public static final String EDIT_EXAMPLE = "edit INDEX [c/COMPANY] [r/ROLE] [s/STAGE] [d/DATETIME] [e/EMAIL] "
+ + "[l/PROGRAMMING LANGUAGE]… [t/TAG]…";
+ public static final String DELETE_HEADER = "Delete an Internship: ";
+ public static final String DELETE_EXAMPLE = "delete INDEX";
+ public static final String CLEAR_HEADER = "Clear all Internships: ";
+ public static final String CLEAR_EXAMPLE = "clear";
+ public static final String LIST_HEADER = "List all Internships: ";
+ public static final String LIST_EXAMPLE = "list";
+ public static final String FIND_HEADER = "Filter Internships: ";
+ public static final String FIND_EXAMPLE = "find c/COMPANY | r/ROLE | s/STAGE";
+ public static final String UNDO_HEADER = "Undo a command: ";
+ public static final String UNDO_EXAMPLE = "undo";
+ public static final String REDO_HEADER = "Redo a command: ";
+ public static final String REDO_EXAMPLE = "redo";
+ public static final String EXIT_HEADER = "Exit application: ";
+ public static final String EXIT_EXAMPLE = "exit";
+ public static final String USERGUIDE_URL = "https://ay2223s1-cs2103t-t10-3.github.io/tp/UserGuide.html";
+ public static final String URL_MESSAGE = "Refer to the user guide for more information: " + USERGUIDE_URL;
+
+ public static final List LIST_OF_HEADERS = Arrays.asList(
+ ADD_HEADER,
+ LIST_HEADER,
+ FIND_HEADER,
+ EDIT_HEADER,
+ DELETE_HEADER,
+ CLEAR_HEADER,
+ UNDO_HEADER,
+ REDO_HEADER,
+ EXIT_HEADER
+ );
+
+ public static final List LIST_OF_EXAMPLES = Arrays.asList(
+ ADD_EXAMPLE,
+ LIST_EXAMPLE,
+ FIND_EXAMPLE,
+ EDIT_EXAMPLE,
+ DELETE_EXAMPLE,
+ CLEAR_EXAMPLE,
+ UNDO_EXAMPLE,
+ REDO_EXAMPLE,
+ EXIT_EXAMPLE
+ );
+
+ public static final Map HEADERS_FOR_COMMAND = new HashMap<>();
+ public static final Map EXAMPLES_FOR_COMMAND = new HashMap<>();
+
+ /**
+ * Contains all commands supported by WB.
+ */
+ public enum Command {
+ ADD, LIST, FIND, EDIT, DELETE, CLEAR, UNDO, REDO, EXIT,
+ }
+
+ /*
+ * Static initialization block to populate the maps.
+ * Each command is mapped to a header and example.
+ */
+ static {
+ for (int i = 0; i < Command.values().length; i++) {
+ HEADERS_FOR_COMMAND.put(Command.values()[i], LIST_OF_HEADERS.get(i));
+ EXAMPLES_FOR_COMMAND.put(Command.values()[i], LIST_OF_EXAMPLES.get(i));
+ }
+ }
+
+ /**
+ * Returns command header for a given command.
+ * @param command Command to return header for.
+ * @return Command header as String.
+ */
+ public static String getCommandHeader(Command command) {
+ return HEADERS_FOR_COMMAND.get(command);
+ }
+
+ /**
+ * Returns command example for a given command.
+ * @param command Command to return example for.
+ * @return Command example as String.
+ */
+ public static String getCommandExample(Command command) {
+ return EXAMPLES_FOR_COMMAND.get(command);
+ }
+
+ public static String getUserGuideUrl() {
+ return USERGUIDE_URL;
+ }
+
+ public static String getUrlMessage() {
+ return URL_MESSAGE;
+ }
+
+}
diff --git a/src/main/resources/images/lightbulb.png b/src/main/resources/images/lightbulb.png
new file mode 100644
index 00000000000..5ade40bb0f5
Binary files /dev/null and b/src/main/resources/images/lightbulb.png differ
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
index 36e6b001cd8..ee13144d236 100644
--- a/src/main/resources/view/DarkTheme.css
+++ b/src/main/resources/view/DarkTheme.css
@@ -350,3 +350,12 @@
-fx-background-radius: 2;
-fx-font-size: 11;
}
+
+#tags .languageTagLabel {
+ -fx-text-fill: white;
+ -fx-background-color: rgb(135, 135, 215);
+ -fx-padding: 1 3 1 3;
+ -fx-border-radius: 2;
+ -fx-background-radius: 2;
+ -fx-font-size: 11;
+}
diff --git a/src/main/resources/view/HelpCard.fxml b/src/main/resources/view/HelpCard.fxml
new file mode 100644
index 00000000000..85390a3f658
--- /dev/null
+++ b/src/main/resources/view/HelpCard.fxml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/HelpWindow.css b/src/main/resources/view/HelpWindow.css
index 17e8a8722cd..a3b604fb5ce 100644
--- a/src/main/resources/view/HelpWindow.css
+++ b/src/main/resources/view/HelpWindow.css
@@ -1,7 +1,21 @@
-#copyButton, #helpMessage {
+#copyButton, #urlMessage {
-fx-text-fill: white;
}
+#topHeader {
+ -fx-text-fill: orange;
+ -fx-font-weight: bold;
+ -fx-font-size: 20px;
+}
+
+.commandText {
+ -fx-text-fill: white;
+}
+
+.commandHeader {
+ -fx-text-fill: orange;
+}
+
#copyButton {
-fx-background-color: dimgray;
}
@@ -14,6 +28,10 @@
-fx-background-color: darkgray;
}
-#helpMessageContainer {
+.commandContainer {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+#urlMessageContainer, #topHeaderContainer {
-fx-background-color: derive(#1d1d1d, 20%);
}
diff --git a/src/main/resources/view/HelpWindow.fxml b/src/main/resources/view/HelpWindow.fxml
index 5dea0adef70..73204360e72 100644
--- a/src/main/resources/view/HelpWindow.fxml
+++ b/src/main/resources/view/HelpWindow.fxml
@@ -3,13 +3,15 @@
-
+
+
+
-
+
@@ -18,27 +20,24 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/InternshipListCard.fxml b/src/main/resources/view/InternshipListCard.fxml
new file mode 100644
index 00000000000..15a605815f4
--- /dev/null
+++ b/src/main/resources/view/InternshipListCard.fxml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+