diff --git a/.gitignore b/.gitignore
index 71c9194e8bd..a8cc1f2863c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,5 @@ src/test/data/sandbox/
# MacOS custom attributes files created by Finder
.DS_Store
docs/_site/
+
+resources/view/puml
diff --git a/README.md b/README.md
index 13f5c77403f..f88f07e0c8c 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)
+# InternEase
+
+InternEase is a **powerful and innovative desktop app designed to streamline the internship application process primarily for Computer Science undergraduates**. With its optimized **combination of a Command Line Interface (CLI) and Graphical User Interface (GUI)**, InternEase offers users the best of both worlds - the speed and efficiency of a CLI for those who can type quickly, and the user-friendly experience of a GUI for those who prefer a visual interface. Whether you’re a seasoned CLI user or a first-time applicant new to work environment, InternEase makes it easy to keep track of your progress, deadlines, and follow-up actions, so you can focus on landing your dream internship.
+
+[![CI Status](https://github.com/AY2223S2-CS2103T-W15-4/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2223S2-CS2103T-W15-4/tp/actions)
+[![codecov](https://codecov.io/gh/AY2223S2-CS2103T-W15-4/tp/branch/master/graph/badge.svg?token=MVV9ABQAS8)](https://codecov.io/gh/AY2223S2-CS2103T-W15-4/tp)
![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.
+## About the project
+
+* This is **a software engineering project done by Team W15-4 from CS2103T (AY2223S2)**.
+* The aim of this project is to:
+ * help Computer Science students to keep track of their internship applications
+ * provide a flexible and efficient internship application management interface via **both CLI and GUI**
+* It is named `InternEase` because it eases the internship application management process via both well-implemented CLI and GUI to help users focus on their internship preparations.
+* For the detailed documentation of this project, see the **[InternEase Product Website](https://ay2223s2-cs2103t-w15-4.github.io/tp/)**.
+
+## Getting started
+* View our [quick start guide](https://ay2223s2-cs2103t-w15-4.github.io/tp/UserGuide.html#quick-start) now to get started on an easier internship journey immediately.
+
+## Acknowledgements
+* The project is based on an ongoing software project for a desktop application (called _AddressBook-Level3_) used for managing contact details by [SE-EDU initiative](https://se-education.org/addressbook-level3/).
diff --git a/build.gradle b/build.gradle
index 108397716bd..c48f16f7fd4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,6 +16,10 @@ repositories {
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
+run {
+ enableAssertions = true;
+}
+
checkstyle {
toolVersion = '10.2'
}
@@ -41,6 +45,7 @@ task coverage(type: JacocoReport) {
}
dependencies {
+ implementation 'org.jetbrains:annotations:23.0.0'
String jUnitVersion = '5.4.0'
String javaFxVersion = '11'
@@ -65,8 +70,12 @@ dependencies {
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: jUnitVersion
}
+run {
+ enableAssertions = true
+}
+
shadowJar {
- archiveFileName = 'addressbook.jar'
+ archiveFileName = 'internEase.jar'
}
defaultTasks 'clean', 'test'
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 00000000000..dffa17d0ea2
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,2 @@
+ignore:
+ - "src/main/java/seedu/address/ui"
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..b0e2cdb70f6 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -5,55 +5,61 @@ title: About Us
We are a team based in the [School of Computing, National University of Singapore](http://www.comp.nus.edu.sg).
-You can reach us at the email `seer[at]comp.nus.edu.sg`
+You can reach us at the email `internease[at]comp.nus.edu.sg`
## Project team
-### John Doe
+### Lee Jia Sheng
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/jiasheng59)]
+[[portfolio](team/jiasheng59.md)]
-* Role: Project Advisor
+* Role: Developer
+* Responsibilities: `Statistics`, `Find` , `Sort` and `Help` feature
-### Jane Doe
+### Lai Hui Qi
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/laihuiqi)]
+[[portfolio](team/laihuiqi.md)]
-* Role: Team Lead
-* Responsibilities: UI
+* Role: Developer
+* Responsibilities: `Clear`, `Clear_by`, `Delete`, `Exit`, `Revert`, `Revert_all` and `Task Package` related features
-### Johnny Doe
+### Benjamin Wee
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/benjamin-wee)] [[portfolio](team/benjamin-wee.md)]
* Role: Developer
-* Responsibilities: Data
+* Responsibilities: `list`, `add_date` and `remind` feature
-### Jean Doe
+### Lau Zhan Ming
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/zm-l)]
+[[portfolio](team/zm-l.md)]
* Role: Developer
-* Responsibilities: Dev Ops + Threading
+* Responsibilities:
+ * Implement feature to manage internship application: `add`, `edit`
+ * GUI for `add`, `edit`, `delete`, `archive`, `unarchive`
-### James Doe
+### Lok Jian Ming
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/jianminglok)]
+[[portfolio](team/jianminglok.md)]
* Role: Developer
-* Responsibilities: UI
+* Responsibilities:
+ * Contact management features: `add_contact`, `edit_contact`, `delete_contact`
+ * Document management features: `add_docs`, `edit_docs`, `delete_docs`
+ * Edit internship application status feature: `edit_status`
+ * Archiving features: `archive`, `unarchive`, `list_archived`
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 46eae8ee565..330025d0800 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -2,14 +2,75 @@
layout: page
title: Developer Guide
---
-* Table of Contents
-{:toc}
+## **Table of Contents**
+ - [Acknowledgements](#acknowledgements)
+ - [Setting up, getting started](#setting-up-getting-started)
+ - [Design](#design)
+ - [Architecture](#architecture)
+ - [UI Component](#ui-component)
+ - [Logic Component](#logic-component)
+ - [Model Component](#model-component)
+ - [Storage Component](#storage-component)
+ - [Common classes](#common-classes)
+ - [Implementation of features](#implementation)
+ - [Add](#add-feature)
+ - [Edit](#edit-feature)
+ - [Add contact](#add-contact-feature)
+ - [Edit contact](#edit-contact-feature)
+ - [Delete contact](#delete-contact-feature)
+ - [List](#list-feature)
+ - [Add documents](#add-documents-feature)
+ - [Edit documents](#edit-documents-feature)
+ - [Delete documents](#delete-documents-feature)
+ - [Edit status](#edit-status-feature)
+ - [Archive](#archive-feature)
+ - [Unarchive](#unarchive-feature)
+ - [List archived applications](#list-archived-applications-feature)
+ - [Find](#find-feature)
+ - [Sort](#sort-feature)
+ - [Clear](#clear-feature)
+ - [Clear by](#clear-by-feature)
+ - [Delete](#delete-feature)
+ - [Revert](#revert-feature)
+ - [Revert all](#revert-all-feature)
+ - [Remind](#remind-feature)
+ - [Exit](#exit-feature)
+ - [Add interview date](#add-interview-date-feature)
+ - [Side features](#side-features)
+ - [Task related features](#task-related-features)
+ - [Find task](#find-task-feature)
+ - [List task](#list-task-feature)
+ - [Todo related features](#todo-related-features)
+ - [Add todo](#add-todo-feature)
+ - [Clear todo](#clear-todo-feature)
+ - [Delete todo](#delete-todo-feature)
+ - [Edit deadline](#edit-deadline-feature)
+ - [Edit content](#edit-content-feature)
+ - [List todo](#list-todo-feature)
+ - [Note related features](#note-related-features)
+ - [Add note](#add-note-feature)
+ - [Clear note](#clear-note-feature)
+ - [Delete note](#delete-note-feature)
+ - [List note](#list-note-feature)
+ - [Documentation, logging, testing, configuration, dev-ops](#documentation-logging-testing-configuration-dev-ops)
+ - [Appendix: Requirements](#appendix-requirements)
+ - [Product Scope](#product-scope)
+ - [User stories](#user-stories)
+ - [Use cases](#use-cases)
+ - [Non functional requirements](#non-functional-requirements)
+ - [Glossary](#glossary)
+ - [Appendix: Instructions for manual testing](#appendix-instructions-for-manual-testing)
+ - [Launch and Shutdown](#launch-and-shutdown)
+ - [Appendix: Planned Enhancement](#appendix-planned-enhancement)
--------------------------------------------------------------------------------------------------------------------
## **Acknowledgements**
-* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+* This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
+* Code and documentations reused and adapted from [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative](https://se-education.org/).
+
+[Go back to Table of Contents](#table-of-contents)
--------------------------------------------------------------------------------------------------------------------
@@ -17,13 +78,15 @@ title: Developer Guide
Refer to the guide [_Setting up and getting started_](SettingUp.md).
+[Go back to Table of Contents](#table-of-contents)
+
--------------------------------------------------------------------------------------------------------------------
## **Design**
-:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/se-edu/addressbook-level3/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
+:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/AY2223S2-CS2103T-W15-4/tp/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
### Architecture
@@ -36,7 +99,7 @@ Given below is a quick overview of main components and how they interact with ea
**Main components of the architecture**
-**`Main`** has two classes called [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java). It is responsible for,
+**`Main`** has two classes called [`Main`](https://github.com/AY2223S2-CS2103T-W15-4/tp/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/AY2223S2-CS2103T-W15-4/tp/tree/master/src/main/java/seedu/address/MainApp.java). It is responsible for,
* At app launch: Initializes the components in the correct sequence, and connects them up with each other.
* At shut down: Shuts down the components and invokes cleanup methods where necessary.
@@ -67,35 +130,45 @@ For example, the `Logic` component defines its API in the `Logic.java` interface
The sections below give more details of each component.
+[Go back to Table of Contents](#table-of-contents)
+
### UI component
-The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java)
+The **API** of this component is specified in [`Ui.java`](https://github.com/AY2223S2-CS2103T-W15-4/tp/blob/master/src/main/java/seedu/address/ui/Ui.java)
-![Structure of the UI Component](images/UiClassDiagram.png)
+![Structure of the UI Component](images/UiClassDiagram.png)
+The reference of the `panels` node is as shown below:
+![refPanels](images/PanelsRef.png)
+The detailed components of `MixedPanel` and `ApplicationListPanel` are as shown below:
+![refMixedPanel](images/MixedPanelRef.png) ![refApplicationPanel](images/ApplicationListPanelRef.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`, `MixedPanel`, `NoteListPanel`, `TodoListPanel` 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)
+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/AY2223S2-CS2103T-W15-4/tp/blob/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2223S2-CS2103T-W15-4/tp/blob/master/src/main/resources/view/MainWindow.fxml)
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 `InternshipApplication` object residing in the `Model`.
+* listens on each other in the `Ui` component, as `CommandBox` calls functions in `MainWindow` to `execute()` `Logic`.
+* keeps a reference to other `Ui` component, as `MainWindow` keeps references of `MixedPanel`, `NoteListPanel`, `ApplicationListPanel` and `TodoListPanel` to implement the switching between each panel.
+
+[Go back to Table of Contents](#table-of-contents)
### Logic component
-**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java)
+**API** : [`Logic.java`](https://github.com/AY2223S2-CS2103T-W15-4/tp/tree/master/src/main/java/seedu/address/logic/Logic.java)
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 `InternEaseParser` 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 application).
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,32 +183,29 @@ 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 `InternEaseParser` 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 `InternEaseParser` 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.
+[Go back to Table of Contents](#table-of-contents)
+
### Model component
-**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java)
+**API** : [`Model.java`](https://github.com/AY2223S2-CS2103T-W15-4/tp/tree/master/src/main/java/seedu/address/model/Model.java)
-
+
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 internship applications data i.e., all `InternshipApplication` objects (which are contained in a `UniqueApplicationList` object).
+* stores the currently 'selected' `Application` 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.
-
-
-
-
-
+[Go back to Table of Contents](#table-of-contents)
### Storage component
-**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java)
+**API** : [`Storage.java`](https://github.com/AY2223S2-CS2103T-W15-4/tp/tree/master/src/main/java/seedu/address/storage/Storage.java)
@@ -144,234 +214,1602 @@ The `Storage` component,
* inherits from both `AddressBookStorage` 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`)
+[Go back to Table of Contents](#table-of-contents)
+
### Common classes
Classes used by multiple components are in the `seedu.addressbook.commons` package.
+[Go back to Table of Contents](#table-of-contents)
+
--------------------------------------------------------------------------------------------------------------------
## **Implementation**
This section describes some noteworthy details on how certain features are implemented.
-### \[Proposed\] Undo/redo feature
+[Go back to Table of Contents](#table-of-contents)
-#### Proposed Implementation
+### Add feature
-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:
+### How add feature is implemented
-* `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.
+The `add` command allows users to add an internship application to the tracker. The add mechanism is facilitated by `AddCommand` class. It extends `Command`but overrides the `Command#execute` to add an internship application to the tracker.
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
+The sequence diagram below shows how the `AddCommand` object is created:
+![AddSequenceDiagram](images/AddSequenceDiagram.png)
-Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
+Step 1. Parsing
-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.
+The `AddCommandParser` checks that the user input is in the expected format, if not an exception will be thrown.
-![UndoRedoState0](images/UndoRedoState0.png)
+Step 2. Execution
-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.
+The `AddCommand#execute` calls `Model#addApplication`, causing an update to the internship list.
-![UndoRedoState1](images/UndoRedoState1.png)
+Step 3. Result
-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`.
+The updated model is then saved. A `CommandResult` object with a message containing the execution result of the command is created and returned to `MainWindow#execute`.
-![UndoRedoState2](images/UndoRedoState2.png)
+[Go back to Table of Contents](#table-of-contents)
-: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`.
+### Edit feature
-
+### How edit feature is implemented
-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.
+The `edit` command allows users to edit an internship application of the tracker. The edit mechanism is facilitated by `EditCommand` class. It extends `Command`but overrides the `Command#execute` to edit an internship application of the tracker.
-![UndoRedoState3](images/UndoRedoState3.png)
+The sequence diagram below shows how the `EditCommand` object is created:
+![EditSequenceDiagram](images/EditSequenceDiagram.png)
-:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather
-than attempting to perform the undo.
+Step 1. Parsing
-
+The `EditCommandParser` checks that the user input is in the expected format, if not an exception will be thrown.
-The following sequence diagram shows how the undo operation works:
+Step 2. Execution
-![UndoSequenceDiagram](images/UndoSequenceDiagram.png)
+The `EditCommand#execute` calls `Model#setApplication`, causing an update to the internship list.
-:information_source: **Note:** The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+Step 3. Result
-
+The updated model is then saved. A `CommandResult` object with a message containing the execution result of the command is created and returned to `MainWindow#execute`.
-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.
+[Go back to Table of Contents](#table-of-contents)
-: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.
+### Add contact feature
-
+#### How is the feature implemented
-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 `add_contact` command allows users to add the contact of a company to an internship application. The implementation of the `add_contact` command is facilitated by the `AddContactCommand` class which is derived from the `Command` superclass, and overrides the `Command#execute` method.
+The parsing process meanwhile involves the `InternEaseParser#parseCommand`, `ContactParser#parseContactCommand` and the `AddContactCommandParser#parse` methods.
-![UndoRedoState4](images/UndoRedoState4.png)
+The activity diagram below shows the workflow of the `add_contact` command during its execution.
-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.
+![AddContactActivityDiagram](images/AddContactActivityDiagram.png)
-![UndoRedoState5](images/UndoRedoState5.png)
+The constructor of the class `AddContactCommand` requires 2 arguments, a valid positive `Integer` index and a `Contact` object, both of which are obtained after the parsing process mentioned above.
-The following activity diagram summarizes what happens when a user executes a new command:
+The relevant operations from the `Model` interface are `Model#getSortedFilteredInternshipList` and `Model#setApplication`.
-
+A sequence diagram is shown here to illustrate the execution process of the `add_contact` command.
-#### Design considerations:
+![AddContactSequenceDiagram](images/AddContactSequenceDiagram.png)
-**Aspect: How undo & redo executes:**
+Given below is an explanation on the `add_contact` command's behaviours.
-* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+Step 1. Parsing
-* **Alternative 2:** Individual command knows how to undo/redo by
- itself.
- * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted).
- * Cons: We must ensure that the implementation of each individual command are correct.
+The `CommandBox#execute` method is invoked when the user's input in `CommandBox` is parsed, which results in the command word being parsed in the method `InternEaseParser#parseCommand` and subsequently the method `ContactParser#parseContactCommand`.
+The method `AddContactCommandParser#parse` is invoked only if the command word matches `AddContactCommand.COMMAND_WORD`.
-_{more aspects and alternatives to be added}_
+Step 2. Execution
-### \[Proposed\] Data archiving
+The `AddContactCommand#execute` method is invoked and calls are made to the `model` instance. The last shown list of internships are obtained by calling the method `Model#getSortedFilteredInternshipList`.
+The internship application where the contact is to be added is then obtained by calling the `UniqueApplicationList#get` method with the specified index. As the InternshipApplication object is
+immutable, a new `InternshipApplication` object is created with the contact details. The `Model#setApplication` method is then invoked to update the specified application in the list.
-_{Explain here how the data archiving feature will be implemented}_
+Step 3. Result
+The updated model is then saved. A `CommandResult` object with a message containing the execution result of the command is created and returned to `MainWindow#execute`.
+The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the returned message for 5 seconds.
---------------------------------------------------------------------------------------------------------------------
+>**NOTE:**
+> Error handling: Any error message returned in the midst of execution will be displayed as a `ResultDialog` and the current command executed terminates immediately.
-## **Documentation, logging, testing, configuration, dev-ops**
+#### Why is it implemented this way
-* [Documentation guide](Documentation.md)
-* [Testing guide](Testing.md)
-* [Logging guide](Logging.md)
-* [Configuration guide](Configuration.md)
-* [DevOps guide](DevOps.md)
+The `AddContactCommand` provides enhancement to the existing `AddCommand` by separating the process of adding contact details of the company from the initial process of
+adding a new internship application. This prevents the `AddCommand` from getting cluttered with large amount of arguments that may become difficult for the user to remember.
---------------------------------------------------------------------------------------------------------------------
+**Aspect: Where to save the contact details:**
-## **Appendix: Requirements**
+* **Alternative 1 (current choice):** Separating it into a separate `Contact` class.
+ * Pros: Flexibility to add more details to the contact if needed in the future.
+ * Cons: More time required to implement.
-### Product scope
+* **Alternative 2:** Adding contact details as attributes in the `InternshipApplication` class.
+ * Pros: Easier than implement.
+ * Cons: More conflicts will occur if someone else is working on the `InternshipApplication` class at the same time.
-**Target user profile**:
+[Go back to Table of Contents](#table-of-contents)
-* has a need to manage a significant number of contacts
-* 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
+### Edit contact feature
+#### How is the feature implemented
-### User stories
+The `edit_contact` command allows users to edit the contact of a company added to an internship application. The implementation of the `edit_contact` command is facilitated by the `EditContactCommand` class which is derived from the `Command` superclass, and overrides the `Command#execute` method.
+The parsing process meanwhile involves the `InternEaseParser#parseCommand`, `ContactParser#parseContactCommand` and the `EditContactCommandParser#parse` methods.
-Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
+The activity diagram below shows the workflow of the `edit_contact` command during its execution.
-| 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 |
+![EditContactActivityDiagram](images/EditContactActivityDiagram.png)
-*{More to be added}*
+The constructor of the class `EditContactCommand` requires 2 arguments, a valid positive `Integer` index and a `EditContactDescriptor` object, both of which are obtained after the parsing process mentioned above.
-### Use cases
+The relevant operations from the `Model` interface are `Model#getSortedFilteredInternshipList` and `Model#setApplication`.
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+A sequence diagram is shown here to illustrate the execution process of the `edit_contact` command.
-**Use case: Delete a person**
+![EditContactSequenceDiagram](images/EditContactSequenceDiagram.png)
-**MSS**
+Given below is an explanation on the `edit_contact` command's behaviours.
-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
+Step 1. Parsing
- Use case ends.
+The `CommandBox#execute` method is invoked when the user's input in `CommandBox` is parsed, which results in the command word being parsed in the method `InternEaseParser#parseCommand` and subsequently the method `ContactParser#parseContactCommand`.
+The method `EditContactCommandParser#parse` is invoked only if the command word matches `EditContactCommand.COMMAND_WORD`.
-**Extensions**
+Step 2. Execution
-* 2a. The list is empty.
+The `EditContactCommand#execute` method is invoked and calls are made to the `model` instance. The last shown list of internships are obtained by calling the method `Model#getSortedFilteredInternshipList`.
+The internship application where the contact is to be edited is then obtained by calling the `UniqueApplicationList#get` method with the specified index. As the InternshipApplication object is
+immutable, a new `InternshipApplication` object is created with the edited contact details. The `Model#setApplication` method is then invoked to update the specified application in the list.
- Use case ends.
+Step 3. Result
-* 3a. The given index is invalid.
+The updated model is then saved. A `CommandResult` object with a message containing the execution result of the command is created and returned to `MainWindow#execute`.
+The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the returned message for 5 seconds.
- * 3a1. AddressBook shows an error message.
+#### Why is it implemented this way
- Use case resumes at step 2.
+The `EditContactCommand` follows the design intuition behind the `AddContactCommand` by separating the process of editing contact details of the company from the process of
+editing other attributes of an existing internship application.
-*{More to be added}*
+[Go back to Table of Contents](#table-of-contents)
-### Non-Functional Requirements
+### Delete contact feature
-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.
+#### How is the feature implemented
-*{More to be added}*
+The `delete_contact` command allows users to delete the contact of a company added to an internship application. The implementation of the `delete_contact` command is facilitated by the `DeleteContactCommand` class which is derived from the `Command` superclass, and overrides the `Command#execute` method.
+The parsing process meanwhile involves the `InternEaseParser#parseCommand`, `ContactParser#parseContactCommand` and the `DeleteContactCommandParser#parse` methods.
-### Glossary
+The activity diagram below shows the workflow of the `delete_contact` command during its execution.
-* **Mainstream OS**: Windows, Linux, Unix, OS-X
-* **Private contact detail**: A contact detail that is not meant to be shared with others
+![DeleteContactActivityDiagram](images/DeleteContactActivityDiagram.png)
---------------------------------------------------------------------------------------------------------------------
+The constructor of the class `DeleteContactCommand` requires 1 argument, a valid positive `Integer` index, which is obtained after the parsing process mentioned above.
-## **Appendix: Instructions for manual testing**
+The relevant operations from the `Model` interface are `Model#getSortedFilteredInternshipList` and `Model#setApplication`.
-Given below are instructions to test the app manually.
+A sequence diagram is shown here to illustrate the execution process of the `delete_contact` command.
-:information_source: **Note:** These instructions only provide a starting point for testers to work on;
-testers are expected to do more *exploratory* testing.
+![DeleteContactSequenceDiagram](images/DeleteContactSequenceDiagram.png)
-
+Given below is an explanation on the `delete_contact` command's behaviours.
-### Launch and shutdown
+Step 1. Parsing
-1. Initial launch
+The `CommandBox#execute` method is invoked when the user's input in `CommandBox` is parsed, which results in the command word being parsed in the method `InternEaseParser#parseCommand` and subsequently the method `ContactParser#parseContactCommand`.
+The method `DeleteContactCommandParser#parse` is invoked only if the command word matches `DeleteContactCommand.COMMAND_WORD`.
- 1. Download the jar file and copy into an empty folder
+Step 2. Execution
- 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
+The `DeleteContactCommand#execute` method is invoked and calls are made to the `model` instance. The last shown list of internships are obtained by calling the method `Model#getSortedFilteredInternshipList`.
+The internship application where the contact is to be edited is then obtained by calling the `UniqueApplicationList#get` method with the specified index. As the InternshipApplication object is
+immutable, a new `InternshipApplication` object is created with the contact details deleted. The `Model#setApplication` method is then invoked to update the specified application in the list.
-1. Saving window preferences
+Step 3. Result
- 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
+The updated model is then saved. A `CommandResult` object with a message containing the execution result of the command is created and returned to `MainWindow#execute`.
+The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the returned message for 5 seconds.
- 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained.
+#### Why is it implemented this way
+
+The `DeleteContactCommand` follows the design intuition behind the `AddContactCommand` by separating the process of deleting contact details of the company from the process of
+deleting other attributes of an existing internship application.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### List feature
+
+#### How is the feature implemented
+
+The `list` command lists all ongoing internship applications, i.e. excluding archived applications. Once the list command is executed,
+it updates the `predicate` of `FilteredInternshipList` in `model` to show only currently ongoing applications. All commands to be executed following this command
+will follow the index of the latest list displayed in the internship application panel.
+
+The execution process of `list_archived` is demonstrated by the activity diagram below.
+
+![ListActivityDiagram](images/ListActivityDiagram.png)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Add documents feature
+
+#### How is the feature implemented
+
+The `add_docs` command allows users to add links of the documents submitted to a company to an internship application. The implementation of the `add_docs` command is facilitated by the `AddDocumentsCommand` class which is derived from the `Command` superclass, and overrides the `Command#execute` method.
+The parsing process meanwhile involves the `InternEaseParser#parseCommand`, `DocumentsParser#parseDocumentsCommand` and the `AddDocumentsCommandParser#parse` methods.
+
+The activity diagram below shows the workflow of the `add_docs` command during its execution.
+
+![AddDocumentsActivityDiagram](images/AddDocumentsActivityDiagram.png)
+
+The constructor of the class `AddDocumentsCommand` requires 2 arguments, a valid positive `Integer` index and a `Documents` object, both of which are obtained after the parsing process mentioned above.
+
+The relevant operations from the `Model` interface are `Model#getSortedFilteredInternshipList` and `Model#setApplication`.
+
+A sequence diagram is shown here to illustrate the execution process of the `add_docs` command.
+
+![AddDocumentsSequenceDiagram](images/AddDocumentsSequenceDiagram.png)
+
+Given below is an explanation on the `add_docs` command's behaviours.
+
+Step 1. Parsing
+
+The `CommandBox#execute` method is invoked when the user's input in `CommandBox` is parsed, which results in the command word being parsed in the method `InternEaseParser#parseCommand` and subsequently the method `DocumentsParser#parseDocumentsCommand`.
+The method `AddDocumentsCommandParser#parse` is invoked only if the command word matches `AddDocumentsCommand.COMMAND_WORD`.
+
+Step 2. Execution
+
+The `AddDocumentsCommand#execute` method is invoked and calls are made to the `model` instance. The last shown list of internships are obtained by calling the method `Model#getSortedFilteredInternshipList`.
+The internship application where the document links are to be added is then obtained by calling the `UniqueApplicationList#get` method with the specified index. As the InternshipApplication object is
+immutable, a new `InternshipApplication` object is created with the document links. The `Model#setApplication` method is then invoked to update the specified application in the list.
+
+Step 3. Result
+
+The updated model is then saved. A `CommandResult` object with a message containing the execution result of the command is created and returned to `MainWindow#execute`.
+The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the returned message for 5 seconds.
+
+#### Why is it implemented this way
+
+The `AddDocumentsCommand` provides enhancement to the existing `AddCommand`, in a similar fashion to the `AddContactCommand`.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Edit documents feature
+
+#### How is the feature implemented
+
+The `edit_docs` command allows users to edit links of the documents submitted to a company to an internship application. The implementation of the `edit_docs` command is facilitated by the `EditDocumentsCommand` class which is derived from the `Command` superclass, and overrides the `Command#execute` method.
+The parsing process meanwhile involves the `InternEaseParser#parseCommand`, `DocumentsParser#parseDocumentsCommand` and the `EditDocumentsCommandParser#parse` methods.
+
+The execution process of the `edit_docs` command can be demonstrated by the activity diagram of `edit_contact` by replacing `contact` related phrases or methods with `documents` related phrases or methods.
+
+> [Edit Contact Feature](#edit-contact-feature)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Delete documents feature
+
+#### How is the feature implemented
+
+The `delete_docs` command allows users to delete links of the documents added to an internship application. The implementation of the `edit_docs` command is facilitated by the `DeleteDocumentsCommand` class which is derived from the `Command` superclass, and overrides the `Command#execute` method.
+The parsing process meanwhile involves the `InternEaseParser#parseCommand`, `DocumentsParser#parseDocumentsCommand` and the `DeleteDocumentsCommandParser#parse` methods.
+
+The execution process of the `delete_docs` command can be demonstrated by the activity diagram of `delete_contact` by replacing `contact` related phrases or methods with `documents` related phrases or methods.
+
+> [Delete Contact Feature](#delete-contact-feature)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Edit status feature
+
+#### How is the feature implemented
+
+The `edit_status` command allows users to edit the status of an internship application. The implementation of the `edit_status` command is facilitated by the `EditStatusCommand` class which is derived from the `Command` superclass, and overrides the `Command#execute` method.
+The parsing process meanwhile involves the `InternEaseParser#parseCommand` and the `EditStatusCommandParser#parse` methods.
+
+The activity diagram below shows the workflow of the `edit_status` command during its execution.
+
+![EditStatusActivityDiagram](images/EditStatusActivityDiagram.png)
+
+The constructor of the class `EditStatusCommand` requires 2 arguments, a valid positive `Integer` index and a `InternshipStatus` object, both of which are obtained after the parsing process mentioned above.
+
+The relevant operations from the `Model` interface are `Model#getSortedFilteredInternshipList` and `Model#setApplication`.
+
+A sequence diagram is shown here to illustrate the execution process of the `edit_contact` command.
+
+![EditStatusSequenceDiagram](images/EditStatusSequenceDiagram.png)
+
+Given below is an explanation on the `edit_status` command's behaviours.
+
+Step 1. Parsing
+
+The `CommandBox#execute` method is invoked when the user's input in `CommandBox` is parsed, which results in the command word being parsed in the method `InternEaseParser#parseCommand`.
+The method `EditStatusCommandParser#parse` is invoked only if the command word matches `EditStatusCommand.COMMAND_WORD`.
+
+Step 2. Execution
+
+The `EditContactCommand#execute` method is invoked and calls are made to the `model` instance. The last shown list of internships are obtained by calling the method `Model#getSortedFilteredInternshipList`.
+The internship application where the status is to be edited is then obtained by calling the `UniqueApplicationList#get` method with the specified index. As the InternshipApplication object is
+immutable, a new `InternshipApplication` object is created with the new status. The `Model#setApplication` method is then invoked to update the specified application in the list.
+
+Step 3. Result
+
+The updated model is then saved. A `CommandResult` object with a message containing the execution result of the command is created and returned to `MainWindow#execute`.
+The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the returned message for 5 seconds.
+
+#### Why is it implemented this way
+
+The `EditStatusCommand` follows the design intuition behind the `EditContactCommand` by separating the process of editing status of the internship application from the process of
+editing other attributes of an existing internship application.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Archive feature
+
+#### How is the feature implemented
+
+The `archive` command allows users to archive an internship application. The implementation of the `archive` command is facilitated by the `ArchiveCommand` class which is derived from the `Command` superclass, and overrides the `Command#execute` method.
+The parsing process meanwhile involves the `InternEaseParser#parseCommand` and the `ArchiveCommandParser#parse` methods.
+
+The activity diagram below shows the workflow of the `archive` command during its execution.
+
+![ArchiveActivityDiagram](images/ArchiveActivityDiagram.png)
+
+The constructor of the class `ArchiveCommand` requires 1 argument, a valid positive `Integer` index, which is obtained after the parsing process mentioned above.
+
+The relevant operations from the `Model` interface are `Model#getSortedFilteredInternshipList` and `Model#setApplication`.
+
+A sequence diagram is shown here to illustrate the execution process of the `archive` command.
+
+![ArchiveSequenceDiagram](images/ArchiveSequenceDiagram.png)
+
+Given below is an explanation on the `archive` command's behaviours.
+
+Step 1. Parsing
+
+The `CommandBox#execute` method is invoked when the user's input in `CommandBox` is parsed, which results in the command word being parsed in the method `InternEaseParser#parseCommand`.
+The method `ArchiveCommandParser#parse` is invoked only if the command word matches `ArchiveCommand.COMMAND_WORD`.
+
+Step 2. Execution
+
+The `ArchiveCommand#execute` method is invoked and calls are made to the `model` instance. The last shown list of internships are obtained by calling the method `Model#getSortedFilteredInternshipList`.
+The internship application to be archived is then obtained by calling the `UniqueApplicationList#get` method with the specified index. As the InternshipApplication object is
+immutable, a new archived `InternshipApplication` object is created. The `Model#setApplication` method is then invoked to update the specified application in the list.
+
+Step 3. Result
+
+The updated model is then saved. A `CommandResult` object with a message containing the execution result of the command is created and returned to `MainWindow#execute`.
+The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the returned message for 5 seconds.
+
+#### Why is it implemented this way
+
+The `ArchiveCommand` allows an internship application to be archived in an easier way, as otherwise the user would have to remember a specific prefix
+if it is implemented as part of the `EditCommand`.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Unarchive feature
+
+#### How is the feature implemented
+
+The `unarchive` command allows users to unarchive an internship application. The implementation of the `unarchive` command is facilitated by the `UnarchiveCommand` class which is derived from the `Command` superclass, and overrides the `Command#execute` method.
+The parsing process meanwhile involves the `InternEaseParser#parseCommand` and the `UnarchiveCommandParser#parse` methods.
+
+The execution process of the `unarchive` command can be demonstrated by the activity diagram of `archive` by replacing `archive` related phrases or methods with `unarchive` related phrases or methods.
+
+> [Archive Feature](#archive-feature)
+
+
+### List archived applications feature
+#### How is the feature implemented
+
+The `list_archived` command lists all currently archived internship applications. The implementation of the `list_archived` command is facilitated by the `ListArchivedCommand` class which is derived from the `Command` superclass, and overrides the `Command#execute` method.
+The execution of the `ListArchivedCommand` is similar to the `ListCommand`.
+
+The execution process of `list_archived` is demonstrated by the activity diagram below.
+
+![ListArchivedActivityDiagram](images/ListArchivedActivityDiagram.png)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Find feature
+
+The `find` command allows user to find all `InternshipApplication` whose
+1. `CompanyName` and `JobTitle` contain the specified keyword, or
+2. `Internship status` contain the specified status, or
+3. `InterviewDate` is before, after, or between specified date(s).
+
+>**NOTE:**
+> The matching of keyword in `CompanyName` and `JobTitle` is case-insensitive. As long as one word within CompanyName`
+> and `JobTitle` matches any of the KEYWORDS, it will be shown in result.
+
+#### How is the feature implemented
+
+The sequence diagram below describes the interaction between classes when find command is entered.
+![FindSequenceDiagram](./images/FindSequenceDiagram.png)
+
+Step 1. Parsing
+
+If the command word matches the word "find", `FindCommandParser#parse()` will be called to parse
+the argument of find. The parsing logic is further divided into three cases below:
+- Case 1: If the prefix `s/` is specified, the argument that follows the prefix immediately is
+deemed as `InternshipStatus`. A `FindStatusCommand` with `StatusPredicate` is created to be executed.
+- Case 2: If one of the following prefixes `before/`, `after/`, OR `from/` and `to/` is specified, the argument
+that follows immediately is deemed as `InterviewDate`. A `FindDateCommand` with appropriate subclasses of
+`DatePredicate` is created to be executed.
+- Case 3: If none of the prefix among `s/`, `before/`, `after/`, `from/`, `to/` is specified
+in the argument. `FindCommandParser` constructs a `FindCommand` object and treat all arguments that follow as `KEYWORD`
+
+Step 2. Execution
+
+The corresponding command is then invoked. Within each command's `execute` method,
+`Model#updateFilteredInternshipList()` is invoked by passing in the predicate. For Cases 1 and 2,
+only those `InternshipApplication`'s with matching `ApplicationStatus` or `InterviewDate` are added to the Model's
+`filteredInternships` whereas for Case 3, if any word within the `CompanyName` or `JobTitle` matches one of the
+`KEYWORD`(s), then that application is added to the Model's `filteredInternships`.
+
+Step 3. Result
+
+The updated model is then saved. A `CommandResult` object with a message containing the execution result of the command
+is created and returned to `MainWindow#execute`. The `ApplicationListPanel` is refreshed with a `ResultDialog`
+displaying the returned message for 5 seconds.
+
+
+#### Why is it implemented this way
+
+The class diagram below shows current structure of classes related to `find` command.
+![FindFeatureClassDiagram](./images/FindFeatureClassDiagram.png)
+
+It is designed and implemented in this way to make the find command more extensible to further enhancement to be made.
+For example, developer may want to enable more prefixes that be searched using the search command. By the
+use of inheritance, one can easily modify the behaviour of `find` command through overrding of the `execute` command
+and rely on polymorphism.
+
+#### Alternatives considered
+
+**Syntax of `find` command**
+
+* **Alternative 1 (current choice):** Now to find attribute in `InternshipApplication`, the command syntax used is
+by using its prefix, i.e. in this form `find s/PENDING`.
+ * Pros: shorter command
+ * Cons: Parser logic is harder to maintain as compared to Alternative 2
+
+* **Alternative 2:** We can also make it in such format find_, e.g. find_status.
+ * Pros: Easy parser to implement
+ * Cons: Longer command which takes longer time to type
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Sort feature
+
+The `sort` command allows user to sort all `InternshipApplication` by the order below:
+1. `CompanyName` (alphabetical order)
+2. `JobTitle` (alphabetical order)
+3. `Internship status` (the default order of status)
+4. `InterviewDate` (ascending order of the interview date, `InternshipApplication` having null values are placed at the end).
+
+>**NOTE:**
+> The alphabetical order for comparing `CompanyName` and `JobTitle` is case-insensitive. To illustrate, the
+> `InternshipApplication` with `CompanyName` "amazon" should appear before that with `CompanyName` "Google".
+
+#### How is the feature implemented
+
+The sequence diagram below describes the interaction between classes when sort command is entered.
+![SortSequenceDiagram](./images/SortSequenceDiagram.png)
+
+Step 1. Parsing
+
+If the command word matches the word "sort", `SortCommandParser#parse()` will be called to parse
+the argument of sort. Depending on the argument of sort, the corresponding comparator will be created. The sort command
+is then created with appropriate comparator.
+
+Step 2. Execution
+
+The SortCommand#execute method is then invoked. The `Model#updateSortedFilteredInternshipList()` is invoked by passing in the comparator.
+The underlying `SortedList` is the updated and sorted by using the Comparator being passed.
+
+Step 3. Result
+
+The updated model is then saved. A `CommandResult` object with a message containing the execution result of the command
+is created and returned to `MainWindow#execute`. The `ApplicationListPanel` is refreshed with a `ResultDialog`
+displaying the returned message for 5 seconds.
+
+
+#### Why is it implemented this way
+
+It is designed and implemented in this way to make the sort command more extensible to further enhancement to be made.
+For example, developer may want to provide more sorting order using the sort command. By the
+use of inheritance, one can easily enhance the `sort` command by passing appropriate implementation of `Comparator` object
+to sort the underlying list of `InternshipApplication`'s by polymorphism.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Clear feature
+This section elaborated the `clear` feature by its functionality and the path of execution together with the `ClearCommand` implementation. Uml diagram is used to aid this description.
+
+#### How CLEAR Feature is implemented
+
+The `clear` feature enables user to clear all internship applications in the current internship application list.
+
+The execution process of `clear` is demonstrated by the sequence diagram below.
+![ClearSequenceDiagram](images/ClearSequenceDiagram.png)
+
+Given below is a step-wise explanation on `clear` mechanism's behaviour.
+
+Step 1. Parsing
+The user input in the `CommandBox` will trigger `CommandBox#execute`, will result in the command word processing in `InternEaseParser#parse`. If the `COMMAND.WORD` matches `clear`.
+
+Step 2. Execution
+`ClearCommand#execute` is called with `model` instance. It attempts to get full list of `Internship Applications` by `Model#getSortedFilteredInternshipList`.
+If the application list is currently not empty, `Model#setInternEase` empties the application list by replacing it with a new InternEase instance while `Model#addAllInternshipToCache` adds the entire list into the cacheList.
+
+Step 3. Result
+The result model is saved. A `CommandResult` with execution result message is returned until the `MainWindow#execute`. The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the execution message for 5 seconds.
+
+>**NOTE:**
+> Error handling: Any error message resulted in the midst of execution will be displayed as a `ResultDialog` and current execution terminates immediately.
+
+#### Why is it implemented this way
+
+The `ClearFeature` is an enhanced extension for the `DeleteFeature`. It provides an execution for a series operations of the `DeleteCommands` at once. Furthermore, it is made reversible by adding the entries into a cacheList immediately after clearing them.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Clear By feature
+This section elaborated the `clear_by` feature by its functionality and the path of execution together with the `ClearByCommand` implementation. Uml diagrams are used to aid this description.
+
+#### How CLEAR_BY Feature is implemented
+
+The `clear_by` feature enables user to clear the internship applications in batch with the specific attribute and the specific keyword. There are 3 cases (attributes) available in this feature.
+In `Logic` interface, `ClearByCommand` extends `Command` with a `ClearByCommand#execute` functionality. The parsing process is facilitated by both the `InternEaseParser#parse` and `ClearByCommandParser#parse`.
+
+The workflow of a `clear_by` command during its execution is shown by the activity diagrams below, the alternatives of the main diagrams are shown in 3 break-downs activity diagram below:
+![ClearByActivityDiagram](images/ClearByActivityDiagram.png)
+Group - Company Name
+![GroupCompanyName](images/GroupCompanyName.png)
+Group - Job Title
+![GroupJobTitle](images/GroupJobTitle.png)
+Group - Status
+![GroupStatus](images/GroupStatus.png)
+
+There are 3 constructors `ClearByCommand::new` provided for 3 different cases stated below :
+
+* Case 1 : clear_by `COMPANY_NAME`
+ * `PREFIX` should be set to `n`
+ * Allows user to remove all internship applications with `ParamType=COMPANY_NAME` **fully match** with the entire provided keyword (case-sensitive).
+
+* Case 2 : clear_by `JOB_TITLE`
+ * `PREFIX` should be set to `j`
+ * Allows user to remove all internship applications with `ParamType=JOB_TITLE` **fully match** with the entire provided keyword (case-sensitive).
+
+* Case 3 : clear_by `STATUS`
+ * `PREFIX` should be set to `s`, the keywords accepted include `ACCEPTED, PENDING, RECEIVED, REJECTED, DECLINED`.
+ * Allows user to remove all internship applications with `ParamType=STATUS` **fully match** with the correct provided keyword (case-sensitive).
+
+>**Note:**
+> The assignation of cases will be done by `ClearByCommandParser#parse`, each unavailable fields will be set to null.
+
+These operations are involved in the `Model` interface as `Model#getSortedFilteredInternshipList`, `Model#addInternshipToCache` and `Model#deleteInternship`
+
+The execution process of `Clear_by` is demonstrated by the sequence diagram below.
+![ClearBySequenceDiagram](images/ClearBySequenceDiagram.png)
+
+Given below is a step-wise explanation on `clear_by` mechanism's behaviour.
+
+Step 1. Parsing
+ The user input in the `CommandBox` will trigger `CommandBox#execute`, will result in the command word processing in `InternEaseParser#parse`. If the `COMMAND.WORD` matches `clear_by`, it will then be passed to `ClearByCommandParser#parse`.
+ The `PREFIX` in the argument will then be investigated. Different constructor of `ClearByCommand` object will be using based on the `PREFIX`.
+
+Step 2. Execution
+ `ClearByCommand#execute` is called with `model` instance. It attempts to get full list of `Internship Applications` by `Model#getSortedFilteredInternshipList`. Then, the list is filtered by `ClearByCommand#getFilteredList` to filter out the applications to be cleared.
+ The size of the list-to-clear is checked before an iteration to `Model#deleteInternship` and `Model#addInternshipToCache`. The cleared items are stored in the cacheList to support `RevertCommand` in current InternEase session.
+
+Step 3. Result
+ The result model is saved. A `CommandResult` with execution result message is returned until the `MainWindow#execute`. The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the execution message for 5 seconds.
+
+>**NOTE:**
+> Error handling: Any error message resulted in the midst of execution will be displayed as a `ResultDialog` and current execution terminates immediately.
+
+#### Why is it implemented this way
+
+The `ClearByCommand` is an enhanced feature for both `DeleteCommand` and `ClearCommand`. It resolves user's request to perform customized batch deletion of internship applications.
+Based on utility, the 3 fixed fields in an internship application are taken as the key attributes for this `clear_by` feature. The `PREFIX` for specifying the `clear_by` attribute is also the same as InternEase convention.
+For the ease of implementation and avoid ambiguity, constructor `ClearByCommand::new` is overloaded, taking different fields. The usage of enum `ParamType` to specify the operating attribute type generalized the `ClearByCommand#execute`.
+The other implementation aspects of `clear_by` feature follow the convention of `InternEase`.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Delete feature
+This section elaborated the `delete` feature by its functionality and the path of execution together with the `DeleteCommand` implementation. Uml diagram is used to aid this description.
+
+#### How DELETE Feature is implemented
+
+The `delete` feature enables user to delete an internship applications with the specified index.
+In `Logic` interface, `DeleteCommand` extends `Command` with a `DeleteCommand#execute` functionality. The parsing process is facilitated by both the `InternEaseParser#parse` and `DeleteCommandParser#parse`.
+
+All the delete operations should only have `INDEX` within the displayed Internship Application List.
+The deleted application(s) in current session (after InternEase initialization, before exit) will be cached in a cacheList to enable the `revert` and `revert_all` features.
+
+These operations are involved in the `Model` interface as `Model#getSortedFilteredInternshipList`, `Model#addInternshipToCache` and `Model#deleteInternship`
+
+The execution process of `delete` is demonstrated by the sequence diagram below.
+![DeleteSequenceDiagram](images/DeleteSequenceDiagram.png)
+
+Given below is a step-wise explanation on `delete` mechanism's behaviour.
+
+Step 1. Parsing
+The user input in the `CommandBox` will trigger `CommandBox#execute`, will result in the command word processing in `InternEaseParser#parse`. If the `COMMAND.WORD` matches `delete`, it will then be passed to `DeleteCommandParser#parse`.
+The `INDEX` in the argument will then be investigated.
+
+Step 2. Execution
+`DeleteCommand#execute` is called with `model` instance. It attempts to get full list of `Internship Applications` by `Model#getSortedFilteredInternshipList`. The `INDEX` is checked against the size of the current Internship Application to ensure that it is within the desired range.
+The `internshipToDelete` is retrieved from the filteredList and deleted from the model by `Model#deleteInternship`. The deleted item is stored in the cacheList to support `RevertCommand` and `RevertAllCommand` in the current InternEase session.
+
+Step 3. Result
+The result model is saved. A `CommandResult` with execution result message is returned until the `MainWindow#execute`. The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the execution message for 5 seconds.
+
+>**NOTE:**
+> Error handling: Any error message resulted in the midst of execution will be displayed as a `ResultDialog` and current execution terminates immediately.
+
+#### Why is it implemented this way
+
+The `DeleteCommand` is a common, must-have feature which helps to clean-up unwanted internship applications to enhance user experience. The cacheList provides an extra protection to the data to buffer the effect of this destructive operation.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Revert feature
+This section elaborated the `revert` feature by its functionality and the path of execution together with the `RevertCommand` implementation. Uml diagram is used to aid this description.
+
+#### How REVERT Feature is implemented
+
+The `revert` feature enables user to revert the most recent deleted internship applications.
+In `Logic` interface, `RevertCommand` extends `Command` with a `RevertCommand#execute` functionality. The parsing process is facilitated by the `InternEaseParser#parse`.
+
+All the revert operations can be operated when the cacheList for the current session is not empty.
+The reverted application(s) in current session (after InternEase initialization, before exit) will be removed from the cacheList and be added to the end of the current internship application list.
+
+These operations are involved in the `Model` interface as `Model#getCachedInternshipList`, `Model#getAndRemoveCachedApplication` and `Model#addApplication`.
+
+The execution process of `revert` is demonstrated by the activity diagram below.
+![RevertActivityDiagram](images/RevertActivityDiagram.png)
+
+Given below is a step-wise explanation on `revert` mechanism's behaviour.
+
+Step 1. Parsing
+The user input in the `CommandBox` will trigger `CommandBox#execute`, will result in the command word processing in `InternEaseParser#parse`. If the `COMMAND.WORD` matches `revert`.
+
+Step 2. Execution
+`RevertCommand#execute` is called with `model` instance. It attempts to get full list of `cached Internship Applications` by `Model#getCachedInternshipList`.
+The `most recent cached Internship Application` is retrieved from the cacheList and deleted from it by `Model#getAndRemoveCachedApplication`. The retrieved item is added back to the end of the internship application list by `Model#addApplication`.
+
+Step 3. Result
+The result model is saved. A `CommandResult` with execution result message is returned until the `MainWindow#execute`. The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the execution message for 5 seconds.
+
+>**NOTE:**
+> Error handling: Any error message resulted in the midst of execution will be displayed as a `ResultDialog` and current execution terminates immediately.
+
+#### Why is it implemented this way
+
+The `RevertFeature` adds an extra cacheList provides an extra protection to the data to counter the destructive effect of the `ClearFeatures` and the `DeleteFeature`. The cacheList does not write in the memory space to provide
+a temporary data-storing data structure that acts as a buffer for the current session's operations.
+
+#### Alternatives considered
+
+**Functionality of `revert` command**
+
+* **Alternative 1 (current choice):** Currently, only the revert of a single deleted / cleared internship application is available.
+ * Pros: Shorter command, easy to implement.
+ * Cons: Less efficient as compared to Alternative 2.
+
+* **Alternative 2:** We can also make it in such format `revert INDEX`, e.g. revert 3 (reverts 3 most recent deleted internship applications).
+ * Pros: More powerful feature.
+ * Cons: More complicate to implement.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Revert All feature
+This section elaborated the `revert_all` feature by its functionality and the path of execution together with the `RevertAllCommand` implementation. Uml diagram is used to aid this description.
+
+#### How REVERT_ALL Feature is implemented
+
+The `revert_all` feature enables user to revert all deleted and cleared internship applications in the current session (after InternEase initialization, before exit).
+
+The execution process of `revert_all` is demonstrated by the sequence diagram below.
+![RevertAllSequenceDiagram](images/RevertAllSequenceDiagram.png)
+
+Given below is a step-wise explanation on `revert_all` mechanism's behaviour.
+
+Step 1. Parsing
+The user input in the `CommandBox` will trigger `CommandBox#execute`, will result in the command word processing in `InternEaseParser#parse`. If the `COMMAND.WORD` matches `revert_all`.
+
+Step 2. Execution
+`RevertAllCommand#execute` is called with `model` instance. It attempts to get full list of `cached Internship Applications` by `Model#getCachedInternshipList`.
+If the cacheList is currently not empty, `Model#setEmptyInternshipCacheList` empties the cacheList while `Model#addApplications` adds the entire list to the end of the current internship application list.
+
+Step 3. Result
+The result model is saved. A `CommandResult` with execution result message is returned until the `MainWindow#execute`. The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the execution message for 5 seconds.
+
+>**NOTE:**
+> Error handling: Any error message resulted in the midst of execution will be displayed as a `ResultDialog` and current execution terminates immediately.
+
+#### Why is it implemented this way
+
+The `RevertAllFeature` is an enhanced extension for the `RevertFeature`. It provides an execution for the series operations of the `RevertFeatures` at once.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Remind feature
+This section elaborated the `remind` by its functionality and the path of execution together with the RemindCommand implementation.
+
+#### How Remind Feature is implemented
+The `remind` feature enables users to view the details of the application with the most imminent interview date.
+
+Given below is a step-wise explanation on `remind` mechanism's behaviour.
+
+Step 1. Parsing
+
+The user input in the `CommandBox` will trigger `CommandBox#execute`, will result in the command word processing in `InternEaseParser#parse`. If the `COMMAND.WORD` matches `remind`.
+
+Step 2. Execution
+
+`RemindCommand#Execute` is called with a model instance. It directly returns a command result with `showReminder` set to `True`.
+
+Step 3. Result
+
+A `CommandResult` with execution result message is returned until the `MainWindow#execute`. The `ResultDialog` displays the execution message for 5 seconds. `MainWindow#handleReminder` handles the remind operation by showing or focusing on the reminder window.
+
+>**NOTE:**
+> Error handling: Any error message resulted in the midst of execution will be displayed as a `ResultDialog` and current execution terminates immediately.
+
+#### Why is it implemented this way
+
+The `RemindFeature` is a good to have feature. Existing reminder window is cleaned-up upon executing commands to prevent multiple windows from clogging up the screen.
+
+[Go back to Table of Contents](#table-of-contents)
-1. _{ more test cases … }_
+### Exit feature
+This section elaborated the `exit` feature by its functionality and the path of execution together with the `ExitCommand` implementation. Uml diagram is used to aid this description.
-### Deleting a person
+#### How Exit Feature is implemented
-1. Deleting a person while all persons are being shown
+The `exit` feature enables user to close InternEase using CLI command.
- 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
+The execution process of `exit` is demonstrated by the sequence diagram below.
+![ExitSequenceDiagram](images/ExitSequenceDiagram.png)
- 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.
+Given below is a step-wise explanation on `exit` mechanism's behaviour.
- 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
+Step 1. Parsing
+The user input in the `CommandBox` will trigger `CommandBox#execute`, will result in the command word processing in `InternEaseParser#parse`. If the `COMMAND.WORD` matches `exit`.
- 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous.
+Step 2. Execution
+`ExitCommand#execute` is called with `model` instance. It directly returns a command result with `exit` parameter being set to `True`.
+
+Step 3. Result
+A `CommandResult` with execution result message is returned until the `MainWindow#execute`. The `ResultDialog` displays the execution message for 5 seconds.
+`MainWindow#handleExit` handle the exit operation by recording current gui settings and hiding all the opened windows. The InternEase software shuts down eventually.
+
+>**NOTE:**
+> Error handling: Any error message resulted in the midst of execution will be displayed as a `ResultDialog` and current execution terminates immediately.
+
+#### Why is it implemented this way
+
+The `ExitFeature` is a general, must-have feature. All the windows are cleaned-up upon exit to prevent illegal running of InternEase processes and the trigger of null-pointer exceptions.
+The `ExitFeature` also acts as the termination point for cacheList usage in the current session.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Add Interview Date feature
+
+#### How is the feature implemented
+
+The `add_date` command allows users to add an interview date to an internship application. The implementation of the `add_date` command is facilitated by the `AddInterviewDateCommand` class which is derived from the `Command` superclass, and overrides the `Command#execute` method.
+The parsing process meanwhile involves the `AddressBookParser#parse#` and the `AddInterviewDateCommandParser#parse` methods.
+
+The constructor of the class `AddInterviewDateCommand` requires 2 arguments, a valid positive `Integer` index and a `InterviewDate` object, both of which are obtained after the parsing process mentioned above.
+
+The relevant operations from the `Model` interface are `Model#getFilteredInternshipList`, `Model#setApplication` and `Model#updateFilteredInternshipList`.
+
+Given below is an explanation on the `add_date` command's behaviours.
+
+Step 1. Parsing
+
+The `CommandBox#execute` method is invoked when the user's input in `CommandBox` is parsed, which results in the command word being parsed in the method `InternEaseParser#parser`.
+The method `AddInterviewDateCommandParser#parse` is invoked only if the command word matches `AddInterviewDateCommand.COMMAND_WORD`.
+
+Step 2. Execution
+
+The `AddInterviewDateCommand#execute` method is invoked and calls are made to the `model` instance. The last shown list of internships are obtained by calling the method `Model#getFilteredInternshipList`.
+The internship application where the interview date is to be added is then obtained by calling the `UniqueApplicationList#get` method with the specified index. As the InternshipApplication object is
+immutable, a new `InternshipApplication` object is created with the interview date. The `Model#setApplication` method is then invoked to update the specified application in the list.
+
+Step 3. Result
+
+The updated model is then saved. A `CommandResult` object with a message containing the execution result of the command is created and returned to `MainWindow#execute`.
+The `ApplicationListPanel` is refreshed with a `ResultDialog` displaying the returned message for 5 seconds.
+
+>**NOTE:**
+> Error handling: Any error message returned in the midst of execution will be displayed as a `ResultDialog` and the current command executed terminates immediately.
+
+#### Why is it implemented this way
+
+The `AddInterviewDateCommand` provides enhancement to the existing `AddCommand` by separating the process of adding the interview date for an application from the initial process of
+adding a new internship application. This prevents the `AddCommand` from getting cluttered with large amount of arguments that may become difficult for the user to remember.
+
+**Aspect: Where to save the interview date details:**
+
+* **Alternative 1 (current choice):** Separating it into a separate `InterviewDate` class.
+ * Pros: Flexibility to add more details to the interview date if needed in the future.
+ * Cons: More time required to implement.
+
+* **Alternative 2:** Adding interview date as an attribute in the `InternshipApplication` class.
+ * Pros: Easier than implement.
+ * Cons: More conflicts will occur if someone else is working on the `InternshipApplication` class at the same time.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Side Features
+**All the side features share similar execution paths as their respective main features execution logic, only minor changes are applied.**
+
+For example, the main differences in these features are on the specific functions used to carry out the execution and the specific lists used to store the relevant items.
+ - `Task` is a combination of `Todo` and `Note`.
+ - `TodoList` or `NoteList` are used instead of the list of InternshipApplications with their related methods.
+ - Methods with `Todo` or `Note` are used instead of `Application` or `Internship` (e.g., updateFiltered`Todo`List and updateFiltered`Note`List are used instead of updateFiltered`Internship`List).
+ - CacheList is not applicable here.
+ - All the commands (include main features) can be executed in any of the panels. It will automatically switch to the related panel and display the results after every execution.
+ - All commands here need to go through the `TaskParser` after being processed in the `InternEaseParser`.
+ - For GUI settings, `Todo` uses `TodoListPanel`, `Note` uses `NoteListPanel`, while `Task` uses `MixedPanel`.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Task related features
+### Find Task feature
+#### How is the feature implemented
+
+The `FindTaskFeature` provides searching function on `Todo` and `Note` with keywords.
+The execution of `FindTaskCommand` is similar to `FindCommand` except it takes no prefix(purely keywords) and it searches on `InternshipTodo` company name and `Note` content.
+
+The execution process of `find_task` is demonstrated by the sequence diagram below.
+![FindTaskSequenceDiagram](images/FindTaskSequenceDiagram.png)
+
+#### Why is it implemented this way
+
+The `FindFeature` on `InternshipTodo` and `Note` are put together as `FindTaskFeature` because they have the same characteristic as a `Task`. It will enable the planning of internship
+application to be more effective.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### List Task feature
+#### How is the feature implemented
+
+The `ListTaskFeature` lists both `TodoList` and `NoteList` all together in a single panel (mixed panel).
+The execution of `ListTaskCommand` is similar to `ListCommand`.
+
+The execution process of `list_task` is demonstrated by the activity diagram below.
+![ListTaskActivityDiagram](images/ListTaskActivityDiagram.png)
+
+#### Why is it implemented this way
+
+By implementing the listing of both `TodoList` and `NoteList` together, user can have a quick overview of current available `Todo Tasks` and long-lasting reminders -- `Notes`.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Todo related features
+### Add Todo feature
+#### How is the feature implemented
+
+The `AddTodoFeature` enables the adding of new `InternshipTodo` instance into the current `TodoList`.
+The execution of `AddTodoCommand` is similar to `AddCommand`, the main difference is `AddTodoCommand` comes with an extra mandatory attribute of `ApplicationDeadline`.
+
+The execution process of `add_todo` is demonstrated by the activity diagram below.
+![AddTodoActivityDiagram](images/AddTodoActivityDiagram.png)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Clear Todo feature
+#### How is the feature implemented
+
+The `ClearTodoFeature` clears the entire `TodoList`.
+The execution of `ClearTodoCommand` is similar to `ClearCommand`. However, cacheList is not available for `InternshipTodo` so this operation is irreversible.
+
+The execution process of `clear_todo` is demonstrated by the activity diagram below.
+![ClearTodoActivityDiagram](images/ClearTodoActivityDiagram.png)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Delete Todo feature
+#### How is the feature implemented
+
+The `DeleteTodoFeature` deletes the specified `InternshipTodo` entry respective to the INDEX stated in the command.
+The execution of `DeleteTodoCommand` is similar to `DeleteCommand`. However, cacheList is not available for `InternshipTodo` so this operation is irreversible.
+
+The execution process of `delete_todo` is demonstrated by the activity diagram below.
+![DeleteTodoActivityDiagram](images/DeleteTodoActivityDiagram.png)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Edit Deadline feature
+#### How is the feature implemented
+
+The `EditDeadlineFeature` enables user to edit the deadline of an `InternshipTodo` with INDEX specified in the command.
+The execution of `EditDeadlineCommand` is similar to `EditStatusCommand`, but it edits the `ApplicationDeadline` for the respective `InternshipTodo`.
+
+The execution process of `edit_deadline` is demonstrated by the sequence diagram below.
+![EditDeadlineSequenceDiagram](images/EditDeadlineSequenceDiagram.png)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Edit Content feature
+#### How is the feature implemented
+
+The `EditContentFeature` enables user to edit the note content of an `InternshipTodo` with INDEX specified in the command.
+The execution of `EditNoteContentCommand` is similar to `EditStatusCommand`, but it edits the `NoteContent` for the respective `InternshipTodo`.
+
+The execution process of `edit_content` is demonstrated by the sequence diagram below.
+![EditNoteContentSequenceDiagram](images/EditNoteContentSequenceDiagram.png)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### List Todo feature
+#### How is the feature implemented
+
+The `ListTodoFeature` lists current `TodoList` in the `TodoListPanel`.
+The execution of `ListTodoCommand` is similar to `ListCommand`.
+
+The execution process of `list_todo` is demonstrated by the activity diagram below.
+![ListTodoActivityDiagram](images/ListTodoActivityDiagram.png)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Note related features
+
+An overview of `Note` package is shown below.
+![NoteOverviewDiagram](images/NoteOverviewDiagram.png)
+
+
+### Add Note feature
+#### How is the feature implemented
+
+The `AddNoteFeature` enables the adding of new `Note` instance into the current `NoteList`.
+The execution of `AddNoteCommand` is similar to `AddCommand`, the main difference is `AddNoteCommand` only has a mandatory attribute `NOTE_CONTENT`.
+
+The execution process of `add_note` can be demonstrated by the activity diagram of `add_todo` by replacing `todo` related phrases or methods to `note` related phrases or methods.
+> [Add Todo Feature](#add-todo-feature)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Clear Note feature
+#### How is the feature implemented
+
+The `ClearNoteFeature` clears the entire `NoteList`.
+The execution of `ClearNoteCommand` is similar to `ClearCommand`. However, cacheList is not available for `Note` so this operation is irreversible.
+
+The execution process of `clear_note` can be demonstrated by the activity diagram of `clear_todo` by replacing `todo` related phrases or methods to `note` related phrases or methods.
+> [Clear Todo Feature](#clear-todo-feature)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Delete Note feature
+#### How is the feature implemented
+
+The `DeleteNoteFeature` deletes the specified `Note` entry respective to the INDEX stated in the command.
+The execution of `DeleteNoteCommand` is similar to `DeleteCommand`. However, cacheList is not available for `Note` so this operation is irreversible.
+
+The execution process of `delete_note` can be demonstrated by the activity diagram of `delete_todo` by replacing `todo` related phrases or methods to `note` related phrases or methods.
+> [Delete Todo Feature](#delete-todo-feature)
+
+[Go back to Table of Contents](#table-of-contents)
+
+### List Note feature
+#### How is the feature implemented
+
+The `ListNoteFeature` lists current `NoteList` in the `NoteListPanel`.
+The execution of `ListNoteCommand` is similar to `ListCommand`.
+
+The execution process of `list_note` can be demonstrated by the activity diagram of `list_todo` by replacing `todo` related phrases or methods to `note` related phrases or methods.
+> [List Todo Feature](#list-todo-feature)
+
+[Go back to Table of Contents](#table-of-contents)
+
+--------------------------------------------------------------------------------------------------------------------
+
+## **Documentation, logging, testing, configuration, dev-ops**
+
+* [Documentation guide](Documentation.md)
+* [Testing guide](Testing.md)
+* [Logging guide](Logging.md)
+* [Configuration guide](Configuration.md)
+* [DevOps guide](DevOps.md)
+
+[Go back to Table of Contents](#table-of-contents)
+
+--------------------------------------------------------------------------------------------------------------------
+
+## **Appendix: Requirements**
+
+### Product scope
+
+**Target user profile**:
+
+* Computer Science undergraduate
+* has a need to manage a number of internship applications
+* prefer desktop apps over other types
+* able to type fast
+* prefers typing to mouse interactions
+* is reasonably comfortable using CLI apps
+
+**Value proposition**: manage internship applications faster and more efficiently than a typical mouse/GUI driven app
+
+[Go back to Table of Contents](#table-of-contents)
+
+### 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 internship application entry | |
+| `* * *` | internship applicant | manage the contact details of the company I am applying to | conveninently contact the company for queries or setting up interviews |
+| `* * *` | internship applicant | note down links to the the documents submmited to the company I am applying to | conveninently retrieve the version of the resume or cover letter submitted to the company |
+| `* * *` | internship applicant | archive my internship application entry | view a list of ongoing internship applications which do not get cluttered over time |
+| `* * *` | internship applicant | delete my submission | remove wrong entries or application that I no longer need |
+| `* * *` | internship applicant | view a list of my internship applications submitted | prevent repeated applications to the same company |
+| `* *` | internship applicant | delete all my applications | start fresh |
+| `* * *` | internship applicant | update the status of my application as it progresses | identify which stage of the application I am in |
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Use cases
+
+(For all use cases below, the **System** is `InternEase` and the **Actor** is the `user`, unless specified otherwise)
+
+**Use case: UC01 Add an internship application entry**
+
+**MSS**
+
+1. User requests to add an internship applications.
+2. InternEase adds the internship application and displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. The command format is invalid.
+ * 1a1. InternEase shows an error message and gives a specific suggestion on the correct command format.
+
+ Use case ends.
+
+**Use case: UC02 Add contact details of a company to an internship application**
+
+**MSS**
+
+1. User requests to view the list of internship applications.
+2. InternEase shows the internship application list with their indexes specified.
+3. User requests to add the contact details of a company to a specific internship application in the list by specifying its respective index and details of the contact.
+4. InternEase adds the contact details of the company to the internship application and displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+ * 2a1. InternEase shows an alert message that there is no internship application in the list.
+
+ Use case ends.
+
+* 3a. The provided index is invalid.
+
+ * 3a1. InternEase shows an error message and gives a specific suggestion on the index's range.
+ * 3a2. User enters a new internship application index.
+
+ Steps 3a1 to 3a2 are repeated until a valid index is provided. Use case resumes at step 4.
+
+* 3b. The provided contact is invalid.
+ * 3b1. InternEase shows an error message and gives a specific suggestion on the format of a valid contact.
+ * 3b2. User enters a new contact.
+
+ Steps 3b1 to 3b2 are repeated until a valid contact is provided. Use case resumes at step 4.
+
+* 3c. The command format is invalid.
+ * 3c1. InternEase shows an error message and gives a specific suggestion on the correct command format.
+ * 3c2. User enters a new command.
+
+ Steps 3c1 to 3c2 are repeated until a valid command is entered. Use case resumes at step 4.
+
+**Use case: UC03 Edit contact details of the company for an internship application**
+
+**MSS**
+
+1. User requests to view the list of internship applications.
+2. InternEase shows the internship application list with their indexes specified.
+3. User requests to edit the contact details of the company for the specific internship application in the list by specifying its respective index and details of the updated contact.
+4. InternEase edits the contact details of the company for the internship application and displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+ * 2a1. InternEase shows an alert message that there is no internship application in the list.
+
+ Use case ends.
+
+* 3a. The provided index is invalid.
+
+ * 3a1. InternEase shows an error message and gives a specific suggestion on the index's range.
+ * 3a2. User enters a new internship application index.
+
+ Steps 3a1 to 3a2 are repeated until a valid index is provided. Use case resumes at step 4.
+
+* 3b. The provided contact is invalid.
+ * 3b1. InternEase shows an error message and gives a specific suggestion on the format of a valid contact.
+ * 3b2. User enters a new contact.
+
+ Steps 3b1 to 3b2 are repeated until a valid contact is provided. Use case resumes at step 4.
+
+* 3c. The command format is invalid.
+ * 3c1. InternEase shows an error message and gives a specific suggestion on the correct command format.
+ * 3c2. User enters a new command.
+
+ Steps 3c1 to 3c2 are repeated until a valid command is entered. Use case resumes at step 4.
+
+**Use case: UC04 Delete contact details of the company for an internship application**
+
+**MSS**
+
+1. User requests to view the list of internship applications.
+2. InternEase shows the internship application list with their indexes specified.
+3. User requests to delete the contact details of the company for the specific internship application in the list by specifying its respective index.
+4. InternEase delete the contact details of the company for the internship application and displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+ * 2a1. InternEase shows an alert message that there is no internship application in the list.
+
+ Use case ends.
+
+* 3a. The provided index is invalid.
+
+ * 3a1. InternEase shows an error message and gives a specific suggestion on the index's range.
+ * 3a2. User enters a new internship application index.
+
+ Steps 3a1 to 3a2 are repeated until a valid index is provided. Use case resumes at step 4.
+
+* 3b. The command format is invalid.
+ * 3b1. InternEase shows an error message and gives a specific suggestion on the correct command format.
+ * 3b2. User enters a new command.
+
+ Steps 3b1 to 3b2 are repeated until a valid command is entered. Use case resumes at step 4.
+
+**Use case: UC05 Add links for documents submitted to the company for an internship application**
+
+Similar to `UC02 Add contact details of a company to an internship application` except that the documents link submitted to a company for an internship application is added.
+
+**Use case: UC06 Edit links for documents submitted to the company for an internship application**
+
+Similar to `UC03 Edit contact details of the company for an internship application` except that the documents link submitted to a company for an internship application is edited.
+
+**Use case: UC07 Delete contact details of the company for an internship application**
+
+Similar to `UC04 Delete contact details of the company for an internship application` except that the documents link submitted to a company for an internship application is deleted.
+
+**Use case: UC08 Revert a recent deleted internship application entry**
+
+**MSS**
+
+1. User accidentally deletes an internship application entry.
+2. User requests to revert the recent execution of delete command.
+3. InterEase retrieves the internship application from the CacheList and add it back to the end of the current internship application list.
+4. InternEase displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 3a. The CacheList is empty.
+ * 3a1. InternEase shows an alert message that there is no deleted internship application can be restored.
+
+ Use case ends.
+
+
+**Use case: UC09 Revert all deleted internship application entries in current session**
+
+**MSS**
+
+1. User accidentally deletes or clears some internship application entries.
+2. User requests to restore all the deleted or cleared entries.
+3. InterEase adds all the cached internship applications back to the end of the current internship application list.
+4. InternEase displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 3a. The CacheList is empty.
+ * 3a1. InternEase shows an alert message that there is no deleted internship application can be restored.
+
+ Use case ends.
+
+
+**Use case: UC10 Delete an internship application entry**
+
+**MSS**
+
+1. User requests to view the list internship applications.
+2. InternEase shows the internship applications list with their indexes specified.
+3. User requests to delete a specific internship application in the list by specifying its respective index.
+4. InterEase deletes the internship application from the list and displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+ * 2a1. InternEase shows an alert message that there is no internship application in the list.
+
+ Use case ends.
+
+* 3a. The given index is invalid.
+ * 3a1. InternEase shows an error message and gives specific suggestion on the index's range.
+
+ * 3a2. User enters new internship application index.
+
+ Steps 3a1 to 3a2 are repeated until a valid index is provided.
+ Use case resumes at step 4.
+
+* 3b. The command format is incorrect.
+
+ * 3b1. InternEase shows an error message and gives specific suggestion on the command format.
+
+ * 3b2. User enters new command.
+
+ Steps 3b1 to 3b2 are repeated until a valid command is provided.
+ Use case resumes at step 4.
+
+**Use case: UC11 Sort internship applications**
+
+**MSS**
+
+1. User specifies the order, either company name, job title, status or interview date for the list of internship
+applications to be sorted.
+2. InternEase shows the sorted list of application ordered by the attribute specified.
+ Use case ends.
+
+**Extensions**
+
+* 1a. User specifies more than one attribute.
+ * 1a1. InternEase notices user that the command format is invalid.
+
+ Use case ends.
+
+**Use case: UC12 Clear all internship application entries**
+
+**MSS**
+
+1. User requests to clear all the data in the application.
+2. InternEase clears all the internship application entries, shows an empty list of internship application data and displays a success message.
+
+ Use case ends.
+
+**Use case: UC13 Edit the status of an internship application**
+
+**MSS**
+
+1. User requests to view the list of internship applications.
+2. InternEase shows the internship application list with their indexes specified.
+3. User requests to edit the application status of a specific internship application in the list by specifying its respective index and the updated status.
+4. InternEase updates the application status of the internship application and displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ * 2a1. InternEase shows an alert message that there is no internship application in the list.
+
+ Use case ends.
+
+* 3a. The provided index is invalid.
+
+ * 3a1. InternEase shows an error message and gives a specific suggestion on the index's range.
+ * 3a2. User enters a new internship application index.
+
+ Steps 3a1 to 3a2 are repeated until a valid index is provided. Use case resumes at step 4.
+
+* 3b. The provided status is invalid.
+
+ * 3b1. InternEase shows an error message and gives a specific suggestion on the possible statuses.
+ * 3b2. User enters a new internship application status.
+
+ Steps 3b1 to 3a2 are repeated until a valid status is provided. Use case resumes at step 4.
+
+* 3c. The command format is invalid.
+ * 3c1. InternEase shows an error message and gives a specific suggestion on the correct command format.
+ * 3c2. User enters a new command.
+
+ Steps 3c1 to 3c2 are repeated until a valid command is entered. Use case resumes at step 4.
+
+**Use case: UC14 Help**
+
+**MSS**
+
+1. User requests for help.
+2. InternEase shows a list of available commands to the user.
+
+**Use case: UC15 List**
+
+**MSS**
+
+1. User requests to view the list of internship applications.
+2. InternEase shows all the ongoing internship applications as a list with their indexes specified.
+
+ Use case ends.
+
+**Extensions**
+* 1a. The list is empty.
+ * 1a1. InternEase shows an alert message that there is no internship application in the list.
+
+ Use case ends.
+
+**Use case: UC16 Clear relevant internship application entries by keyword**
+
+**MSS**
+
+1. User requests to view the list of internship applications.
+2. InternEase shows the internship application list with their attributes specified.
+3. User requests to clear all the relevant entries with specific keyword and its attribute.
+4. InternEase requests confirmation from user.
+5. InternEase updates the application status of the internship application and displays a success message.
+
+ Use case ends.
+
+**Extensions**
+* 1a. The list is empty.
+ * 1a1. InternEase shows an alert message that there is no internship application in the list.
+
+ Use case ends.
+
+* 2a. The provided attribute is invalid.
+ * 2a1. InternEase shows an error message and gives a specific suggestion on the correct command format.
+ * 2a2. User enters a new command.
+
+ Steps 2a1 to 2a2 are repeated until a valid attribute is provided. Use case resumes at step 4.
+
+**Use case: UC17 Archive an internship application**
+
+**MSS**
+
+1. User requests to view the list of internship applications.
+2. InternEase shows the internship application list with their indexes specified.
+3. User requests to archive a specific internship application in the list by specifying its respective index.
+4. InternEase archives the internship application and displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ * 2a1. InternEase shows an alert message that there is no internship application in the list.
+
+ Use case ends.
+
+* 3a. The provided index is invalid.
+
+ * 3a1. InternEase shows an error message and gives a specific suggestion on the index's range.
+ * 3a2. User enters a new internship application index.
+
+ Steps 3a1 to 3a2 are repeated until a valid index is provided. Use case resumes at step 4.
+
+* 3b. The command format is invalid.
+ * 3b1. InternEase shows an error message and gives a specific suggestion on the correct command format.
+ * 3b2. User enters a new command.
+
+ Steps 3b1 to 3b2 are repeated until a valid command is entered. Use case resumes at step 4.
+
+* 3c. The specified internship application is already archived.
+
+ * 3a1. InternEase shows an error message.
+
+ Use case ends.
+
+**Use case: UC18 Unarchive an internship application**
+
+Similar to `UC17 Archive an internship application` except that the internship application is unarchived.
+
+**Use case: UC19 List archived internship applications**
+
+Similar to `UC15 List` except that only archived internship applications are shown.
+
+**Use case: UC20 Find an application by its company name and job title**
+
+**MSS**
+
+1. User specifies keyword for matching company name and job title for the internship application.
+2. InternEase shows a list of application whose company name or job title fulfill the matching keyword.
+ Use case ends.
+
+**Extensions**
+
+* 1a. The list is empty.
+ * 1a1. InternEase notices user that there is no internship application in the list.
+
+ Use case ends.
+
+**Use case: UC21 Find an application by its status**
+
+Similar to `UC20 Find an application by its company name and job title` except it's now finding by status.
+
+**Use case: UC22 Find an application by the range of interview date**
+
+Similar to `UC20 Find an application by its company name and job title` except user specifies a range of date when the interview date falls within.
+
+### Side features
+
+**Use case: UC23 Add a todo task entry**
+
+Similar to `UC01 Add an internship application entry` except todo task is added instead of an internship application.
+
+**Use case: UC24 List todo**
+
+Similar to `UC15 List` except todo tasks are listed instead of internship applications.
+
+**Use case: UC25 Edit the note content of a todo task**
+
+Similar to `UC13 Edit the status of an internship application` except the note content of a todo task is edited.
+
+**Use case: UC26 Edit the deadline of a todo task**
+
+Similar to `UC13 Edit the status of an internship application` except the deadline of a todo task is edited.
+
+**Use case: UC27 Delete a todo task entry**
+
+Similar to `UC10 Delete an internship application entry` except the specified todo task is deleted.
+
+**Use case: UC28 Clear all todo task entries**
+
+Similar to `UC12 Clear all internship application entries` except all the todo task entries are cleared instead of all the internship application entries.
+
+**Use case: UC29 Add a note**
+
+Similar to `UC01 Add an internship application entry` except a note entry is added instead of an internship application.
+
+**Use case: UC30 List note**
+
+Similar to `UC15 List` except note entries are listed instead of internship applications.
+
+**Use case: UC31 Delete a note entry**
+
+Similar to `UC10 Delete an internship application entry` except the specified note entry is deleted.
+
+**Use case: UC32 Clear all note entries**
+
+Similar to `UC12 Clear all internship application entries` except all the notes entries are cleared instead of all the internship application entries.
+
+**Use case: UC33 List task**
+
+Similar to `UC15 List` except todo task entries and note entries are listed instead of internship applications.
+
+**Use case: UC34 Find a task by its field**
+
+Similar to `UC20 Find an application by its company name and job title` except todo task entries and note entries which match the specified keyword are filtered out and listed.
+
+**Use case: UC35 Edit an internship application**
+
+**MSS**
+
+1. User requests to view the list of internship applications.
+2. InternEase shows the internship application list with their indexes specified.
+3. User requests to edit the details of specific internship application in the list by specifying its index.
+4. InternEase edits the details of the internship application and displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+ * 2a1. InternEase shows an alert message that there is no internship application in the list.
+
+ Use case ends.
+
+* 3a. The provided index is invalid.
+
+ * 3a1. InternEase shows an error message and gives a specific suggestion on the index's range.
+ * 3a2. User enters a new internship application index.
+
+ Steps 3a1 to 3a2 are repeated until a valid index is provided. Use case resumes at step 4.
+
+* 3b. The provided details is invalid.
+ * 3b1. InternEase shows an error message and gives a specific suggestion on the format of valid details.
+ * 3b2. User enters new details.
+
+ Steps 3b1 to 3b2 are repeated until valid details is provided. Use case resumes at step 4.
+
+* 3c. The command format is invalid.
+ * 3c1. InternEase shows an error message and gives a specific suggestion on the correct command format.
+ * 3c2. User enters a new command.
+
+ Steps 3c1 to 3c2 are repeated until a valid command is entered. Use case resumes at step 4.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### 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 internship applications without a noticeable increase in 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 typing commands than using the mouse.
+4. InternEase doesn't support storing the actual file for the resume and cover letter. User can only include links to their resume and cover letter used for a particular application.
+5. InternEase is unable to remind user through any platform outside of the application.
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Glossary
+
+* **CLI**: Command line interface
+* **GUI**: Graphical User interface
+* **Mainstream OS**: Windows, Linux, Unix, OS-X
+* **InternshipTodo**: Internships that are planned to apply
+* **Note**: Act as long-lasting reminders for future internship applications and interviews
+
+[Go back to Table of Contents](#table-of-contents)
+
+--------------------------------------------------------------------------------------------------------------------
+
+## **Appendix: Instructions for manual testing**
+
+Given below are instructions to test the app manually.
+
+:information_source: **Note:** These instructions only provide a starting point for testers to work on;
+testers are expected to do more *exploratory* testing.
+
+
+
+[Go back to Table of Contents](#table-of-contents)
+
+### Launch and shutdown
+
+1. Initial launch of InternEase
+
+ 1. Download the jar file and copy into an empty folder
+ 2. Launch the application by:
+ 1. Double-click the jar file.
+ or
+ 2. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar InternEase.jar` command to run the program.
+ Expected: Shows the GUI with a set of sample internship applications. The window size may not be optimal.
+
+2. Saving window preferences
+
+ 1. Resize the window to an optimal size. Move the window to a different location. Close the window.
+
+ 2. Re-launch the app by double-clicking the jar file.
+ Expected: The most recent window size and location is retained.
-1. _{ more test cases … }_
+3. Shutting down InternEase
+ 1. Shut down InternEase
+ 1. Using `exit` command.
+ or
+ 2. Close the window using the 'X' button on top-right of the window frame.
+ 2. All prior activities will be saved.
+ 3. Re-launch InternEase by [Step 1(ii)](#Launch-and-shutdown).
Expected: All the saved data will be loaded and displayed.
-### Saving data
+[Go back to Table of Contents](#table-of-contents)
-1. Dealing with missing/corrupted data files
+## **Appendix: Planned Enhancement**
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
+1. The current display duration may not suit everyone and the dialog content looks messy on showing all particulars. The display duration could be customized (can be decided by user) and the dialog content could be enhanced to show important particulars only in further enhancement.
+2. All commands are executable on any panel (e.g., command `delete_note 2` can delete the 2nd note even though the panel is showing the todo list only). We plan to have some enhancement on it by implementing some custom restrictions (can be decided by user) to limit the command executions according to the displaying GUI.
+3. The current method of displaying the details of an internship application by clicking the card on the left panel to display it on the right panel is less ideal to users who prefer to perform operations solely via CLI. We plan to enhance their user experience by including a `view` command in future iterations, allowing them to
+ show the details of an internship application on the right panel by including an `INDEX` when typing in the command.
+4. The current method for managing documents used for an internship application only supports `HTTP` and `HTTPS` links to those documents. We plan to enhance this feature by allowing users to upload the files directly to our app, so that they can view the file immediately without an Internet connection.
-1. _{ more test cases … }_
+[Go back to Table of Contents](#table-of-contents)
diff --git a/docs/SettingUp.md b/docs/SettingUp.md
index 275445bd551..53d9110f486 100644
--- a/docs/SettingUp.md
+++ b/docs/SettingUp.md
@@ -45,7 +45,7 @@ If you plan to use Intellij IDEA (highly recommended):
1. **Learn the design**
- When you are ready to start coding, we recommend that you get some sense of the overall design by reading about [AddressBook’s architecture](DeveloperGuide.md#architecture).
+ When you are ready to start coding, we recommend that you get some sense of the overall design by reading about [InternEase’s architecture](DeveloperGuide.md#architecture).
1. **Do the tutorials**
These tutorials will help you get acquainted with the codebase.
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index e7df68b01ea..061f35e4d81 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -3,39 +3,111 @@ 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}
+InternEase is a powerful and innovative desktop app designed to streamline the internship application process primarily
+for Computer Science undergraduates. With its optimized combination of a Command Line Interface (CLI)
+and Graphical User Interface (GUI), InternEase offers users the best of both worlds - the speed and efficiency of a CLI
+for those who can type quickly, and the user-friendly experience of a GUI for those who prefer a visual interface.
+Whether you're a seasoned CLI user or a first-time applicant new to work environment, InternEase makes it easy
+to keep track of your progress, deadlines, and follow-up actions, so you can focus on landing your dream internship.
+
+## Features Menu
+- [Quick start](#quick-start)
+
+- [Features](#features)
+
+- [Main Features](#main-features-tracking-applied-internships)
+ - [View guide : `help`](#view-help--help)
+ - [Manage an internship application](#add-an-internship-application--add)
+ - [Add an internship application : `add`](#add-an-internship-application--add)
+ - [Edit an internship application : `edit`](#edit-an-internship-application--edit)
+ - [List currently ongoing internship applications : `list`](#display-a-list-of-ongoing-internship-applications--list)
+ - [Sort all internship applications : `sort`](#sort-all-internship-applications--sort)
+ - [Find internship applications by the company name, job title, status, or interview date : `find`](#find-internship-applications-by-the-company-name-job-title-status-or-interview-date--find)
+ - [Add an interview date : `add_date`](#add-an-interview-date--add_date)
+ - [Manage company contact for an internship application](#add-contact-details--add_contact)
+ - [Add a company contact : `add_contact`](#add-contact-details--add_contact)
+ - [Edit a company contact : `edit_contact`](#edit-contact-details--edit_contact)
+ - [Delete a company contact : `delete_contact`](#delete-contact-details--delete_contact)
+ - [Edit the status of an internship application : `edit_status`](#edit-application-status--edit_status)
+ - [Manage documents for an internship application](#add-documents--add_docs)
+ - [Add documents : `add_docs`](#add-documents--add_docs)
+ - [Edit documents : `edit_docs`](#edit-documents--edit_docs)
+ - [Delete documents : `delete_docs`](#delete-documents--delete_docs)
+ - [Archive and unarchive an internship application](#archive-an-internship-application--archive)
+ - [Archive an application : `archive`](#archive-an-internship-application--archive)
+ - [Unarchive an application : `unarchive`](#unarchive-an-internship-application--unarchive)
+ - [List all archived applications : `list_archived`](#display-a-list-of-archived-internship-applications--list_archived)
+ - [Displaying reminders : `remind`](#displaying-the-internship-application-with-the-most-imminent-interview--remind)
+ - [Remove entry(entries)](#delete-an-internship-application--delete)
+ - [Delete an internship application : `delete`](#delete-an-internship-application--delete)
+ - [Clear all internship applications : `clear`](#clear-all-internship-application-entries--clear)
+ - [Clear specific internship applications : `clear_by`](#clear-internship-application-entries-with-keyword--clear_by)
+ - [Revert delete or clear](#revert-a-recently-deleted-internship-application--revert)
+ - [Revert the most recent delete command : `revert`](#revert-a-recently-deleted-internship-application--revert)
+ - [Revert all delete and clear commands : `revert_all`](#revert-all-recently-deleted-or-cleared-internship-applications--revert_all)
+ - [Exit InternEase : `exit`](#exit-the-program--exit)
+
+- [Side Features](#side-features-planning-to-apply-internships)
+ - [Task (todo and notes)](#display-lists-of-tasks-todos-and-notes--list_task)
+ - [List current available tasks : `list_task`](#display-lists-of-tasks-todos-and-notes--list_task)
+ - [Find specific tasks : `find_task`](#search-for-a-task-todo-and-notes--find_task)
+ - [Todo](#display-a-list-of-todo-internship-applications--list_todo)
+ - [List current available todo internship applications : `list_todo`](#display-a-list-of-todo-internship-applications--list_todo)
+ - [Add a todo internship application : `add_todo`](#add-a-todo-application--add_todo)
+ - [Edit the deadline of a todo task : `edit_deadline`](#edit-todo-application-deadline--edit_deadline)
+ - [Edit the note content of a todo task : `edit_content`](#edit-todo-note-content--edit_content)
+ - [Delete a todo task : `delete_todo`](#delete-a-todo-application--delete_todo)
+ - [Clear all todo tasks : `clear_todo`](#clear-all-todo-application-entries--clear_todo)
+ - [Note](#display-list-of-short-note--list_note)
+ - [List current saved notes : `list_note`](#display-list-of-short-note--list_note)
+ - [Add a note : `add_note`](#add-a-note-add_note)
+ - [Delete a note : `delete_note`](#delete-a-note--delete_note)
+ - [Clear all notes : `clear_note`](#clear-all-notes---clear_note)
+
+- [FAQ](#faq)
+
+- [Command Summary](#command-summary)
--------------------------------------------------------------------------------------------------------------------
## Quick start
-1. Ensure you have Java `11` or above installed in your Computer.
+> **Note**
+> This is a desktop app.
+
+1. Have Java `11` or above installed in local laptop or Computer.
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+2. Download the latest version (InternEase v1.4) of `internease.jar` from [here](https://github.com/AY2223S2-CS2103T-W15-4/tp/releases).
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+3. Copy the file to the folder you want to use as the _home folder_ for your InternEaseApp.
-1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar addressbook.jar` command to run the application.
- A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
+4. Start the app by:
+ - Opening a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar internease.jar` command to run the program.
+ or
+ - Double-clicking the downloaded `internease.jar` file.
+ > **Note**
+ > You should see the app is running now. A 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.
+5. 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:
- * `list` : Lists all contacts.
+ * `add n/TechCompany j/Software Engineer` : Adds an application for the `Software Engineer` role at `TechCompany`.
+
+ * `list` : Displays all the internships that the user has applied for.
+
+ * `delete 2` : Deletes the second internship application in the list of applications.
- * `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.
+ * `find TechCompany` : Searches for all application with `COMPANY_NAME` and/or `JOB_TITLE` as `Google`
- * `delete 3` : Deletes the 3rd contact shown in the current list.
+ * `edit_status 2 s/PENDING` : Changes the status of the 2nd application in the applications list to `Pending offer`.
- * `clear` : Deletes all contacts.
+ * `exit` : Exits the application.
- * `exit` : Exits the app.
+6. Refer to the [Features](#features) below for details of each command.
-1. Refer to the [Features](#features) below for details of each command.
+[↑ Back to Top of Section](#quick-start)
+[↑ Back to Features Menu](#features-menu)
--------------------------------------------------------------------------------------------------------------------
@@ -46,137 +118,601 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo
**:information_source: 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 n/COMPANY_NAME`, `COMPANY_NAME` is a parameter which can be used as `add n/LinkedIn`.
* 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 `n/COMPANY_NAME [l/LOCATION]` can be used as `n/LinkedIn l/Clementi` or as `n/LinkedIn`.
* 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. `[r/REVIEW]…` can be used as ` ` (i.e. 0 times), `r/Close to MRT`, `r/Close to MRT t/Kind, inclusive bosses and colleagues` etc.
* Parameters can be in any order.
- e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable.
+ e.g. if the command specifies `n/COMPANY_NAME j/JOB_TITLE`, `j/JOB_TITLE n/COMPANY_NAME` 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.
+ e.g. if you specify `l/Clementi l/Changi`, only `l/Changi` will be taken.
-* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
+* Note that the following are reserved keyword in InternEase, and including these characters in the company name, job title,
+ review, and other fields may lead to unspecified behaviour:
+ * `n/`, `j/`, `r/`, `p/`, `q/`, `l/`, `s/`, `note/`, `rate/`, `reflect/`, `e/`, `by/`, `c/`, `d/`, `rs/`, `cl/`, `before/`, `after/`, `from/`, `to/`,
+
+* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit`,`clear`, and `remind`) will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`.
+* >**Note:**
+ > InternEase has 4 window interfaces which include the internship application list, the todo list, the note list and the task list.
+ > All the commands can be used in any interface. If the command for a different interface is executed in current interface, the current interface will switch to the respective interface and display the result of the command.
+
+GUI Breakdown:
+![GuiOverview](images/ui/GuiOverview.png)
+
-### Viewing help : `help`
+[↑ Back to Top of Section](#features)
+[↑ Back to Features Menu](#features-menu)
-Shows a message explaning how to access the help page.
+## Main features: Tracking applied internships
-![help message](images/helpMessage.png)
+### View help : `help`
+Shows user the link to user guide.
Format: `help`
+[↑ Back to Features Menu](#features-menu)
-### Adding a person: `add`
+### Add an internship application : `add`
-Adds a person to the address book.
+Adds an internship application to the tracker
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+Format: `add n/COMPANY_NAME j/JOB_TITLE [l/LOCATION] [s/SALARY] [rate/RATING] [q/QUALIFICATION]... [p/PROGRAMMINGLANGUAGE]... [r/REVIEW]... [note/NOTE]... [reflect/REFLECTION]...`
+- `SALARY` should be in the form of amount followed by a space and then the currency in upper case.
-:bulb: **Tip:**
-A person can have any number of tags (including 0)
-
+Examples:
+* `add n/Facebook j/Product Manager` adds an application for the Product Manager role at Facebook.
+* `add n/LinkedIn j/Software Engineer s/2000 SGD` adds an application for the Software Engineer role at LinkedIn with salary 2000 SGD.
+
+GUI alternative:
+1. Click the button to add a new internship application.
+2. A popup window similar to the image below will appear.
+
+3. Fields that are marked with red asterisk are compulsory fields while others are optional fields.
+4. You can fill in the fields accordingly and press the `Add` button to execute the `add` command.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Edit an internship application : `edit`
+
+Edits the internship .
+
+Format: `edit INDEX [n/COMPANY_NAME] [j/JOB_TITLE] [l/LOCATION] [s/SALARY] [rate/RATING] [q/QUALIFICATION]... [p/PROGRAMMINGLANGUAGE]... [r/REVIEW]... [note/NOTE]... [reflect/REFLECTION]...`
+
+- Edits the internship application at the specified `INDEX`.
+- The index refers to the index number shown in the displayed internship list.
+- The index must be a positive integer 1, 2, 3, …
+- If `COMPANY_NAME` or `JOB_TITLE` is empty in the form, they will retain the former value, but the `COMPANY_NAME` or `JOB_TITLE` in CLI command cannot be empty.
+- Other attribute can be left as empty string.
Examples:
-* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01`
-* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal`
+* `edit 1 q/Singapore citizen q/Pursuing CS degree` updates the qualification of the internship with first index to `Singapore citizen` and `Pursuing CS degree`.
+* `edit 2 n/LinkedIn j/Data Engineer` updates the second internship company name to `LinkedIn` and job title to `Data Engineer`.
+
+GUI alternative:
+1. Click the button to edit an internship application.
+2. A popup window similar to the image below will appear.
+
+3. You can fill in the fields accordingly and press the `Edit` button to execute the `edit` command.
-### Listing all persons : `list`
+[↑ Back to Features Menu](#features-menu)
-Shows a list of all persons in the address book.
+### Display a list of ongoing internship applications : `list`
+
+Displays a list of applied internships which are ongoing
Format: `list`
-### Editing a person : `edit`
+Examples:
+
+* `list` shows all the ongoing internship applications for with 1 indexing.
+* If there are no ongoing internship applications at the moment,
+ "No applications at the moment" will be shown.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Sort all internship applications : `sort`
+
+Sorts internship applications according to either company name, job title, status or interview date in ascending order.
+
+Format: `sort PREFIX`
+1. Sort by company name: `sort n/`
+2. Sort by job title: `sort j/`
+3. Sort by status: `sort s/`
+4. Sort by interview date `sort d/`
+
+Example:
+* `sort d/` sorts all applications with their interview date in ascending order, those without interview date available
+ yet will be placed at the end of the list.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Find internship applications by the company name, job title, status, or interview date : `find`
+
+Find all internship applications (including those that have been archived) by its company name, job title,
+status and/or interview date.
+
+Format:
+There are three use cases for the `find` command:
+1. Find by the application's company name and/or job title: `find KEYWORD [MORE KEYWORDS]`
+2. Find by the current status of the application: `find s/STATUS`
+3. Find by upcoming interview date: `find before/DATE`, `find after/DATE_TIME`, `find from/DATE_TIME1 to/DATE_TIME2`
+
+- The search for company name, job title, and status are case-insensitive.
+- The order of KEYWORD doesn't matter.
+- In use case 1, as long as a single word in company name and/or job title matches one of the KEYWORD's, it
+ will be shown to user. E.g. `JP Morgan` and `goldman Sachs` matches the keyword in `find JP Morgan Goldman Sachs`.
+- Only full word will be matched. E.g. `goldman Sachs` won't match `find GOLD`.
+
+Examples:
+* `find Google` searches for all application with `COMPANY_NAME` and/or `JOB_TITLE` as Google.
+* `find s/PENDING` searches for all application that are pending.
+* `find after/2023-12-02 12:30 PM` searches for all application that are having interview after
+ 2023-12-02 12:30 PM (inclusive).
+
+[↑ Back to Features Menu](#features-menu)
+
+### Add an interview date : `add_date`
+
+Adds an interview date and time to an internship application.
+
+Format: `add_date INDEX d/DATE_TIME`
+
+- Adds an interview date to the internship application at the specified `INDEX`.
+- The index refers to the index number shown in the displayed internship list.
+- The index must be a positive integer 1, 2, 3, …
+- `DATE_TIME` should be a valid date time of the format `yyyy-MM-dd hh:mm a`, where `a` is either `AM` or `PM`, and the date and time must be after the current date and time.
+- If the internship application at the specified `INDEX` already has an interview date, the previous interview date will be overwritten by the new one.
+
+Examples:
+* `add_date 1 d/2023-05-02 11:30 AM` adds the date and time 2023-05-02 11:30 AM to the first application in the list of applications.
+* `add_date 2 d/2023-07-03 12:30 PM` adds the date and time 2023-07-03 12:30 PM to the second application in the list of applications.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Add contact details : `add_contact`
+
+Adds the contact details of a company to a specified application.
+
+Format: `add_contact INDEX p/PHONE_NUMBER e/EMAIL`
+
+- Adds contact details to the internship application at the specified `INDEX`.
+- The index refers to the index number shown in the displayed internship list.
+- The index must be a positive integer 1, 2, 3, …
+- **Both** the phone number and email must be provided.
+- `PHONE_NUMBER` should be a valid phone number of at least 3 digits.
+- `EMAIL` should be a valid email of the format `username@domain.com`.
+
+Examples:
+* `add_contact 1 p/87654321 e/abc@gmail.com` adds the contact number `87654321` and email `abc@gmail.com` to the 1st application in the list of applications.
+* `add_contact 2 p/65432100 e/someemail@gmail.com` adds the contact number `65432100` and the email `someemail@gmail.com` to the 2nd application in the list of applications.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Edit contact details : `edit_contact`
+
+Edits the contact details of a company previously added to a specified application.
+
+Format: `edit_contact INDEX [p/PHONE_NUMBER] [e/EMAIL]`
+
+- Edits contact details of the internship application at the specified `INDEX`.
+- The index refers to the index number shown in the displayed internship list.
+- The index must be a positive integer 1, 2, 3, …
+- **At least one** field should be provided.
+- `PHONE_NUMBER` should be a valid phone number of at least 3 digits.
+- `EMAIL` should be a valid email of the format `username@domain.com`.
-Edits an existing person in the address book.
+Examples:
+* `edit_contact 1 p/87654321 e/abc@gmail.com` updates the contact number and email of the company to `87654321` and `abc@gmail.com` respectively for the 1st application in the list of applications.
+* `edit_contact 2 e/someemail@gmail.com` updates the email of the company to `someemail@gmail.com` for the 2nd application in the list of applications.
+* `edit_contact 3 p/12345678` updates the contact number of the company to `12345678` for the 3rd application in the list of applications.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Delete contact details : `delete_contact`
+
+Deletes the contact details of a company previously added to a specified application.
+
+Format: `delete_contact INDEX`
+
+- Deletes contact details added to the internship application at the specified `INDEX`.
+- The index refers to the index number shown in the displayed internship list.
+- The index must be a positive integer 1, 2, 3, …
+
+Examples:
+* `delete_contact 1` deletes the contact number and email of the company for the 1st application in the list of applications.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Edit application status : `edit_status`
+
+Edits the application status.
+
+Format: `edit_status INDEX s/STATUS`
+- Edits the status of the specified `INDEX` to the specified `STATUS`.
+- The index refers to the index number shown in the displayed internship list.
+- The index must be a positive integer 1, 2, 3, …
+- Available status: PENDING, RECEIVED, ACCEPTED, DECLINED, REJECTED
+ - PENDING: Internship application submitted, outcome has not been released.
+ - RECEIVED: Offer received.
+ - ACCEPTED: Offer accepted.
+ - DECLINED: Offer received and declined.
+ - REJECTED: Application rejected.
+
+Examples:
+* `edit_status 2 s/PENDING` Changes the status of the 2nd application in the applications list to `PENDING` (Internship application submitted, outcome has not been released).
+
+[↑ Back to Features Menu](#features-menu)
+
+### Add documents : `add_docs`
+
+Adds documents including a resume link and a cover letter link to a specified application.
+
+Format: `add_docs INDEX rs/RESUME_LINK cl/COVER_LETTER_LINK`
+
+- The index refers to the index number shown in the displayed internship list.
+- The index must be a positive integer 1, 2, 3, …
+- **Both** the resume link and the cover letter link must be provided.
+- `RESUME_LINK` must be a valid URL in the format `http://domain/path` or `https://domain/path`.
+- `COVER_LETTER_LINK` must be a valid URL in the format `http://domain/path` or `https://domain/path`.
+
+Examples:
+* `add_docs 1 rs/https://www.example.com/resume cl/https://www.example.com/coverletter` adds the resume link `https://www.example.com/resume`
+ and cover letter link `https://www.example.com/coverletter` to the 1st application in the list of applications.
+* `add_docs 2 rs/https://www.goodresume.com/myresume cl/https://www.goodcoverletter.com/mycoverletter` adds the resume link `https://www.goodresume.com/myresume`
+ and cover letter link `https://www.goodcoverletter.com/mycoverletter` to the 2nd application in the list of applications.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Edit documents : `edit_docs`
+
+Edits the documents which include the resume link and cover letter link previously added to a specified application.
+
+Format: `edit_docs INDEX [rs/RESUME_LINK] [cl/COVER_LETTER_LINK]`
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+- The index refers to the index number shown in the displayed internship list.
+- The index must be a positive integer 1, 2, 3, …
+- **At least one** field should be provided.
+- `RESUME_LINK` must be a valid URL in the format `http://domain/path` or `https://domain/path`.
+- `COVER_LETTER_LINK` must be a valid URL in the format `http://domain/path` or `https://domain/path`.
-* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index **must be a positive integer** 1, 2, 3, …
-* At least one of the optional fields must be provided.
-* Existing values will be updated to the input values.
-* When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative.
-* You can remove all the person’s tags by typing `t/` without
- specifying any tags after it.
+Examples:
+* `edit_docs 1 rs/https://www.example.com/resume cl/https://www.example.com/coverletter` updates the resume link and cover letter link to `https://www.example.com/resume`
+ and `https://www.example.com/coverletter` respectively for the 1st application in the list of applications.
+* `edit_docs 2 rs/https://www.example.com/resume` updates the resume link to `https://www.example.com/resume` for the 2nd application in the list of applications.
+* `edit_docs 3 cl/https://www.example.com/coverletter` updates the cover letter link to `https://www.example.com/coverletter` for the 3rd application in the list of applications.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Delete documents : `delete_docs`
+
+Deletes the documents previously added to a specified application.
+
+Format: `delete_docs INDEX`
+
+- The index refers to the index number shown in the displayed internship list.
+- The index must be a positive integer 1, 2, 3, …
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.
+* `delete_docs 1` deletes the documents for the 1st application in the list of applications.
+
+[↑ Back to Features Menu](#features-menu)
-### Locating persons by name: `find`
+### Archive an internship application : `archive`
-Finds persons whose names contain any of the given keywords.
+Archives a specified application so that it would be hidden from the list of ongoing applications.
-Format: `find KEYWORD [MORE_KEYWORDS]`
+Format: `archive INDEX`
-* 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`
+- The index refers to the index number shown in the displayed internship list.
+- The index must be a positive integer 1, 2, 3, …
Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png)
+* `archive 1` archives the 1st application in the list of applications.
+
+GUI alternative:
+1. Click the button to archive an internship application that is not archived.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Unarchive an internship application : `unarchive`
+
+Unarchives a specified application that was previously archived so that it would be shown in the list of ongoing applications.
+
+Format: `unarchive INDEX`
+
+- The index refers to the index number shown in the displayed internship list.
+- The index must be a positive integer 1, 2, 3, …
+
+Examples:
+* `unarchive 1` unarchives the 1st application in the list of archived applications.
+
+GUI alternative:
+1. Click the button to unarchive an internship application that is archived.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Display a list of archived internship applications : `list_archived`
+
+Displays a list of archived internship applications.
+
+Format: `list_archived`
+
+- If there are no archived internship applications at the moment, "No archived applications at the moment" will be shown.
+
+Examples:
+
+* `list_archived` shows all the archived internship applications with 1 indexing.
+
+[↑ Back to Features Menu](#features-menu)
-### Deleting a person : `delete`
+### Delete an internship application : `delete`
-Deletes the specified person from the address book.
+Deletes the specified internship application from the list of internships applied.
Format: `delete INDEX`
-* Deletes the person at the specified `INDEX`.
-* The index refers to the index number shown in the displayed person list.
+* Deletes the application of internship at the specified `INDEX`.
+* The index refers to the index number shown in the displayed internship list.
* The index **must be a positive integer** 1, 2, 3, …
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.
+* `delete 2` Deletes the 2nd internship application in the list of applications.
-### Clearing all entries : `clear`
+GUI alternative:
+1. Click the button to delete an internship application.
-Clears all entries from the address book.
+[↑ Back to Features Menu](#features-menu)
+
+### Clear internship application entries with keyword : `clear_by`
+
+Clear all relevant internship application entries from the internship tracker with specific keyword.
+
+Format: `clear_by n/COMPANY_NAME` OR `clear_by j/JOB_TITLE` OR `clear_by s/STATUS`
+
+* Clears all internship applications with the specified keyword - `COMPANY_NAME`, `JOB_TITLE` or `STATUS`.
+* As a protective approach, only internship applications with desired particulars that are **fully matched** with the entire, case-sensitive keyword will be cleared.
+* Three types of clear_by features are provided, they can only be executed independently.
+
+Examples:
+* `clear_by n/Meta` Clears all application with COMPANY_NAME as Meta.
+* `clear_by j/Software engineer` Clears all application with JOB_TITLE as Software Engineer.
+* `clear_by s/REJECTED` Clears all rejected application (with STATUS as REJECTED).
+
+[↑ Back to Features Menu](#features-menu)
+
+### Displaying the internship application with the most imminent interview : `remind`
+
+Displays the details of an internship application with the earliest date in a pop up window, with reference to the
+current date and time.
+
+Format: `remind`
+
+[↑ Back to Features Menu](#features-menu)
+
+### Clear all internship application entries : `clear`
+
+Clears all internship application entries from the internship tracker.
Format: `clear`
-### Exiting the program : `exit`
+[↑ Back to Features Menu](#features-menu)
+
+### Revert a recently deleted internship application : `revert`
+
+Reverts the most recent delete command and restores the relevant data to the end of the current internship applications list.
+
+Format: `revert`
+
+Examples:
+1. Assume the most recent delete command was `delete 2` which has data `n/Tech j/Job`, the data was removed from the applications list.
+2. Command `revert` restores the internship application entry at the back the application list, which has an effect similar to `add n/Tech j/Job`.
+
+**This command is only able to restore current session's data, all the deleted / cleared data will be permanently deleted if command `exit` is executed.**
+
+[↑ Back to Features Menu](#features-menu)
+
+### Revert all recently deleted or cleared internship applications : `revert_all`
+
+Reverts all recent delete commands or clear commands and restores the affected data back to the end of the current internship applications list.
+
+Format: `revert_all`
+
+**This command is only able to restore current session's data, all the deleted / cleared data will be permanently deleted if command `exit` is executed.**
+
+[↑ Back to Features Menu](#features-menu)
+
+### Exit the program : `exit`
Exits the program.
Format: `exit`
-### Saving the data
+[↑ Back to Features Menu](#features-menu)
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+## Side features: Planning to apply internships
-### Editing the data file
+### Display lists of tasks (todos and notes) : `list_task`
-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.
+Displays the todo-list and the note list together.
-: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.
-
+Format: `list_task`
+
+Examples:
+
+* `list_task` shows all the todos and notes in one window.
+* If there are no todo and note at the moment, `No task (todo and note) at the moment` will be shown in the result dialog.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Search for a task (todo and notes) : `find_task`
+
+Searches the recorded lists of todos and notes by keyword (company name in todos and note content in notes).
+
+Format: `find_task KEYWORD`
+
+Searches for the todos or notes with the specified case-insensitive `KEYWORD`.
+The keyword refers to the company name in todos or the note content in notes that the user intends to look for.
+
+Examples:
+`find_task test week` searches for all todos with `COMPANY_NAME` or all notes with `NOTE_CONTENT` that contain `test` or `week`.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Display a list of todo internship applications : `list_todo`
+
+Displays a list of todo applications (todo internship application).
+
+Format: `list_todo`
+
+Examples:
+
+* `list_todo` shows all the todo applications that the user has recorded.
+* If there are no todo applications for at the moment, `No todo at the moment` will be shown.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Add a todo application : `add_todo`
+
+Adds a todo internship application to the todo list.
+
+Format: `add_todo n/COMPANY_NAME j/JOB_TITLE by/DEADLINE`
+- `DEADLINE` should be in the format yyyy-mm-dd.
+- `DEADLINE` should not be earlier than the date when the todo application is created.
+
+Examples:
+* `add_todo n/Facebook j/Product Manager by/2023-06-07` adds a todo application for the Product Manager role at Facebook. The internship should be applied by 7 June 2023.
+* `add_todo n/LinkedIn j/Software Engineer by/2023-10-04` adds a todo application for the Software Engineer role at LinkedIn.The internship should be applied by 4 October 2023.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Edit todo application deadline : `edit_deadline`
-### Archiving data files `[coming in v2.0]`
+Edits the deadline of the specified todo task from current available todo liss.
-_Details coming soon ..._
+Format: `edit_deadline INDEX by/DEADLINE`
+- Edits the deadline of the specified `INDEX` to the specified `DEADLINE`.
+- The index refers to the index number shown in the displayed todo list.
+- The index must be a positive integer 1, 2, 3, …
+- `DEADLINE` should be in the format yyyy-mm-dd.
+- `DEADLINE` should not be earlier than the date when the todo application is created.
+
+Examples:
+* `edit_deadline 2 by/2023-07-06` Changes the deadline of the 2nd todo application in the todo list to `2023-07-06` (6 July 2023).
+
+[↑ Back to Features Menu](#features-menu)
+
+### Edit todo note content : `edit_content`
+
+Edits the note content of the specified todo task from current available todo list.
+
+Format: `edit_content INDEX c/NOTE_CONTENT`
+- Edits the note content of the specified `INDEX` to the specified `NOTE_CONTENT`.
+- The index refers to the index number shown in the displayed todo list.
+- The index must be a positive integer 1, 2, 3, …
+- **Note content is an optional field for todo applications**
+- `NOTE_CONTENT` is empty (null) in default.
+- `NOTE_CONTENT` can take 1 to 55 characters.
+
+Examples:
+* `edit_content 2 c/Venue changed` Changes the note content of the 2nd todo application in the todo list to `Venue changed`.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Delete a todo application : `delete_todo`
+
+Deletes the specified todo application from the todo list
+
+Format: `delete_todo INDEX`
+
+* Deletes the todo application at the specified `INDEX`.
+* The index refers to the index number shown in the displayed todo list.
+* The index **must be a positive integer** 1, 2, 3, …
+* **This action is irreversible**
+
+Examples:
+* `delete_todo 2` Deletes the 2nd todo application in the todo list.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Clear all todo application entries : `clear_todo`
+
+Clears all todo application entries from the todo applications list.
+
+Format: `clear_todo`
+
+**This action is irreversible**
+
+[↑ Back to Features Menu](#features-menu)
+
+### Display list of short note : `list_note`
+
+Displays a list of saved notes.
+
+Format: `list_note`
+
+Examples:
+* `list_note` shows all the notes that the user has written.
+* If there are no internships applied for at the moment, `No note at the moment` will be shown.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Add a note: `add_note`
+
+Adds a note to the note list.
+
+Format: `add_note c/NOTE_CONTENT`
+- `NOTE_CONTENT` can take 1 to 55 characters.
+
+Examples:
+* `add_note c/Focus on software engineering jobs!` adds a note with content `Focus on software engineering jobs!` into the note list.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Delete a note : `delete_note`
+
+Deletes the specified note from the list of notes.
+
+Format: `delete_note INDEX`
+
+* Deletes the note at the specified `INDEX`.
+* The index refers to the index number shown in the displayed note list.
+* The index **must be a positive integer** 1, 2, 3, …
+* **This action is irreversible**
+
+Examples:
+* `delete_note 2` Deletes the 2nd note in the list of notes.
+
+[↑ Back to Features Menu](#features-menu)
+
+### Clear all notes : `clear_note`
+
+Clears all notes from the note.
+
+Format: `clear_note`
+
+**This action is irreversible**
+
+[↑ Back to Features Menu](#features-menu)
--------------------------------------------------------------------------------------------------------------------
## FAQ
**Q**: How do I transfer my data to another Computer?
-**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous AddressBook home folder.
+**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 InternEase home folder.
+
+**Q**: How do I update the statistics at bottom right corner?
+**A**: It's automatically update after you execute every command / action via either CLI or GUI.
+
+[↑ Back to Features Menu](#features-menu)
--------------------------------------------------------------------------------------------------------------------
@@ -184,10 +720,42 @@ _Details coming soon ..._
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`
+**Add** | `add n/COMPANY_NAME j/JOB_TITLE [l/LOCATION] [s/SALARY] [rate/RATING] [q/QUALIFICATION]... [p/PROGRAMMINGLANGUAGE]... [r/REVIEW]... [note/NOTE]... [reflect/REFLECTION]...`
e.g., `add n/LinkedIn j/Software Engineer s/2000 SGD`
+**Add Contact** | `add_contact INDEX p/PHONE_NUMBER e/EMAIL`
e.g., `add_contact 1 p/87654321 e/abc@gmail.com`
+**Add Documents** | `add_docs INDEX rs/RESUME_LINK cl/COVER_LETTER_LINK`
e.g., `add_docs 1 rs/https://www.example.com/resume cl/https://www.example.com/coverletter`
+**Add Interview Date** | `add_date INDEX d/DATE_TIME`
e.g., `add_date 1 d/2023-05-02 11:30 AM`
+**Add Note** |`add_note c/NOTE_CONTENT`
e.g., `add_note c/The tasks are planned to be done by tomorrow!`
+**Add Todo** |`add_todo n/COMPANY_NAME J/JOB_TITLE by/DEADLINE`
e.g., `add_todo n/company j/Manager d/2023-09-08`
+**Archive** | `archive INDEX`
e.g., `archive 2`
+**Clear** | `clear`
+**Clear_by** | `clear_by n/COMPANY_NAME`
`clear_by j/JOB_TITLE`
`clear_by s/STATUS`
+**Clear Note** |`clear_note`
+**Clear Todo** |`clear_todo`
+**Delete** | `delete INDEX`
e.g., `delete 2`
+**Delete Contact** | `delete_contact INDEX`
e.g., `delete_contact 2`
+**Delete Documents** | `delete_docs INDEX`
e.g., `delete_docs 2`
+**Delete Note** |`delete_note INDEX`
e.g., `delete_note 2`
+**Delete Todo** |`delete_todo INDEX`
e.g., `delete_todo 2`
+**Edit** | `edit INDEX [n/COMPANY_NAME] [j/JOB_TITLE] [l/LOCATION] [s/SALARY] [rate/RATING] [q/QUALIFICATION]... [p/PROGRAMMINGLANGUAGE]... [r/REVIEW]... [note/NOTE]... [reflect/REFLECTION]...`
e.g., `edit 1 q/Singapore citizen q/Pursuing CS degree`
+**Edit Contact** | `edit_contact INDEX [p/PHONE_NUMBER] [e/EMAIL]`
e.g., `edit_contact 3 p/98765432 e/def@gmail.com`
+**Edit Documents** | `edit_docs INDEX [rs/RESUME_LINK] [cl/COVER_LETTER_LINK]`
e.g., `edit_docs 2 rs/https://www.goodresume.com/myresume cl/https://www.goodcoverletter.com/mycoverletter`
+**Edit Deadline** |`edit_deadline INDEX by/DEADLINE`
e.g., `edit_deadline 2 by/2023-06-05`
+**Edit Note Content** |`edit_content c/NOTE_CONTENT`
e.g., `edit_content 2 c/Venue changed`
+**Edit Status** | `edit_status INDEX s/STATUS`
e.g., `edit_status 2 s/PENDING`
+**Exit** | `exit`
+**Find Applications** | `find KEYWORD [MORE KEYWORDS]`
e.g., `find Google`
`find s/STATUS`
e.g., `find s/PENDING`
`find before/DATE`, `find after/DATE_TIME`, `find from/DATE_TIME1 to/DATE_TIME2`
e.g., `find before/2023-01-31 12:45 PM`
+**Find Task** |`find_task KEYWORD`
e.g., `find_task test`
**Help** | `help`
+**List** |`list`
+**List Archived Applications** |`list_archived`
+**List Note** |`list_note`
+**List Task** |`list_task`
+**List Todo** |`list_todo`
+**Reminder** | `remind`
+**Revert** | `revert`
+**Revert All** | `revert_all`
+**Sort Applications** | `sort n/`
`sort j/`
`sort s/`
`sort d/`
+**Unarchive** | `unarchive INDEX`
e.g., `unarchive 2`
+
+[↑ Back to Top of Section](#command-summary)
+[↑ Back to Features Menu](#features-menu)
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..4522e32bd98 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,4 +1,4 @@
-title: "AB-3"
+title: "InternEase"
theme: minima
header_pages:
@@ -8,7 +8,7 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "AY2223S2-CS2103T-W15-4/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..22aa2bf198b 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: "InternEase";
font-size: 32px;
}
}
diff --git a/docs/diagrams/AddContactActivityDiagram.puml b/docs/diagrams/AddContactActivityDiagram.puml
new file mode 100644
index 00000000000..29219124caf
--- /dev/null
+++ b/docs/diagrams/AddContactActivityDiagram.puml
@@ -0,0 +1,22 @@
+@startuml
+start
+:User enters command add_contact;
+if () then ([PREFIX p/ and e/ are present])
+ :Parse command arguments;
+ if () then ([Phone number and email are valid])
+ :Generate new AddContactCommand;
+ if () then ([Provided index is valid])
+ :Add contact details to the specified application;
+ :Generate success message;
+ else ([else])
+ :Generate error message;
+ endif
+ else ([else])
+ :Generate error message;
+ endif
+ else ([else])
+ :Generate error message;
+endif
+:Display result message to user;
+stop
+@enduml
diff --git a/docs/diagrams/AddContactSequenceDiagram.puml b/docs/diagrams/AddContactSequenceDiagram.puml
new file mode 100644
index 00000000000..f6eaa19a7e3
--- /dev/null
+++ b/docs/diagrams/AddContactSequenceDiagram.puml
@@ -0,0 +1,75 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":ContactParser" as ContactParser LOGIC_COLOR
+participant ":AddContactCommandParser" as AddContactCommandParser LOGIC_COLOR
+participant "a:AddContactCommand" as AddContactCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute(add_contact)
+activate LogicManager
+
+LogicManager -> InternEaseParser : parseCommand(add_contact)
+activate InternEaseParser
+
+create ContactParser
+InternEaseParser -> ContactParser : parseContactCommand(add_contact, args)
+activate ContactParser
+
+create AddContactCommandParser
+ContactParser -> AddContactCommandParser
+activate AddContactCommandParser
+
+AddContactCommandParser --> ContactParser
+deactivate AddContactCommandParser
+
+ContactParser -> AddContactCommandParser : parse(args)
+activate AddContactCommandParser
+
+create AddContactCommand
+AddContactCommandParser -> AddContactCommand
+activate AddContactCommand
+
+AddContactCommand --> AddContactCommandParser : a
+deactivate AddContactCommand
+
+AddContactCommandParser --> ContactParser : a
+deactivate AddContactCommandParser
+AddContactCommandParser -[hidden]-> InternEaseParser : result
+destroy AddContactCommandParser
+
+ContactParser --> InternEaseParser : a
+deactivate ContactParser
+
+InternEaseParser --> LogicManager : a
+deactivate InternEaseParser
+
+LogicManager -> AddContactCommand : execute()
+activate AddContactCommand
+
+AddContactCommand -> Model : setApplication(original, contactAdded)
+activate Model
+
+Model --> AddContactCommand
+deactivate Model
+
+create CommandResult
+AddContactCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> AddContactCommand : r
+deactivate CommandResult
+
+AddContactCommand --> LogicManager : r
+deactivate AddContactCommand
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/AddDocumentsActivityDiagram.puml b/docs/diagrams/AddDocumentsActivityDiagram.puml
new file mode 100644
index 00000000000..19ec02b3180
--- /dev/null
+++ b/docs/diagrams/AddDocumentsActivityDiagram.puml
@@ -0,0 +1,22 @@
+@startuml
+start
+:User enters command add_docs;
+if () then ([PREFIX rs/ and cl/ are present])
+ :Parse command arguments;
+ if () then ([Resume and cover letter links are valid])
+ :Generate new AddDocumentsCommand;
+ if () then ([Provided index is valid])
+ :Add document links to the specified application;
+ :Generate success message;
+ else ([else])
+ :Generate error message;
+ endif
+ else ([else])
+ :Generate error message;
+ endif
+ else ([else])
+ :Generate error message;
+endif
+:Display result message to user;
+stop
+@enduml
diff --git a/docs/diagrams/AddDocumentsSequenceDiagram.puml b/docs/diagrams/AddDocumentsSequenceDiagram.puml
new file mode 100644
index 00000000000..eef1c1b8c8c
--- /dev/null
+++ b/docs/diagrams/AddDocumentsSequenceDiagram.puml
@@ -0,0 +1,75 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":DocumentsParser" as DocumentsParser LOGIC_COLOR
+participant ":AddDocumentsCommandParser" as AddDocumentsCommandParser LOGIC_COLOR
+participant "a:AddDocumentsCommand" as AddDocumentsCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute(add_docs)
+activate LogicManager
+
+LogicManager -> InternEaseParser : parseCommand(add_docs)
+activate InternEaseParser
+
+create DocumentsParser
+InternEaseParser -> DocumentsParser : parseDocumentsCommand(add_docs, args)
+activate DocumentsParser
+
+create AddDocumentsCommandParser
+DocumentsParser -> AddDocumentsCommandParser
+activate AddDocumentsCommandParser
+
+AddDocumentsCommandParser --> DocumentsParser
+deactivate AddDocumentsCommandParser
+
+DocumentsParser -> AddDocumentsCommandParser : parse(args)
+activate AddDocumentsCommandParser
+
+create AddDocumentsCommand
+AddDocumentsCommandParser -> AddDocumentsCommand
+activate AddDocumentsCommand
+
+AddDocumentsCommand --> AddDocumentsCommandParser : a
+deactivate AddDocumentsCommand
+
+AddDocumentsCommandParser --> DocumentsParser : a
+deactivate AddDocumentsCommandParser
+AddDocumentsCommandParser -[hidden]-> InternEaseParser : result
+destroy AddDocumentsCommandParser
+
+DocumentsParser --> InternEaseParser : a
+deactivate DocumentsParser
+
+InternEaseParser --> LogicManager : a
+deactivate InternEaseParser
+
+LogicManager -> AddDocumentsCommand : execute()
+activate AddDocumentsCommand
+
+AddDocumentsCommand -> Model : setApplication(original, documentsAdded)
+activate Model
+
+Model --> AddDocumentsCommand
+deactivate Model
+
+create CommandResult
+AddDocumentsCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> AddDocumentsCommand : r
+deactivate CommandResult
+
+AddDocumentsCommand --> LogicManager : r
+deactivate AddDocumentsCommand
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/AddSequenceDiagram.puml b/docs/diagrams/AddSequenceDiagram.puml
new file mode 100644
index 00000000000..93d7821acad
--- /dev/null
+++ b/docs/diagrams/AddSequenceDiagram.puml
@@ -0,0 +1,61 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":AddCommandParser" as AddCommandParser LOGIC_COLOR
+participant "a:AddCommand" as AddCommand LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute(add)
+activate LogicManager
+
+LogicManager -> InternEaseParser: parseCommand(add)
+activate InternEaseParser
+
+create AddCommandParser
+InternEaseParser -> AddCommandParser : AddCommandParser()
+activate AddCommandParser
+
+AddCommandParser --> InternEaseParser
+deactivate AddCommandParser
+
+InternEaseParser -> AddCommandParser : parse(arguments)
+activate AddCommandParser
+create AddCommand
+AddCommandParser -> AddCommand : AddCommand(internship)
+activate AddCommand
+
+AddCommand --> AddCommandParser
+deactivate AddCommand
+
+AddCommandParser --> InternEaseParser : a
+deactivate AddCommandParser
+AddCommandParser -[hidden]--> InternEaseParser : a
+destroy AddCommandParser
+
+InternEaseParser --> LogicManager : a
+deactivate InternEaseParser
+
+LogicManager -> AddCommand : execute()
+activate AddCommand
+
+AddCommand -> Model : addApplication(internship)
+activate Model
+
+Model --> AddCommand
+deactivate Model
+
+AddCommand --> LogicManager : result
+deactivate AddCommand
+AddCommand -[hidden]--> LogicManager
+destroy AddCommand
+
+<-- LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/AddTodoActivityDiagram.puml b/docs/diagrams/AddTodoActivityDiagram.puml
new file mode 100644
index 00000000000..51882101016
--- /dev/null
+++ b/docs/diagrams/AddTodoActivityDiagram.puml
@@ -0,0 +1,16 @@
+@startuml
+start
+:User enters AddTodoCommand;
+ if () then ([Input Argument is valid])
+ :Generate new AddTodoCommand;
+ if () then ([Todo to add already exists in the current TodoList])
+ :Generate duplicate Todo alert;
+ else ([else])
+ :Add Todo into TodoList;
+ :Generate success message;
+ endif
+ else ([else])
+ :Generate error message;
+ endif
+stop
+@enduml
diff --git a/docs/diagrams/ApplicationListPanelRef.puml b/docs/diagrams/ApplicationListPanelRef.puml
new file mode 100644
index 00000000000..8b04226904f
--- /dev/null
+++ b/docs/diagrams/ApplicationListPanelRef.puml
@@ -0,0 +1,37 @@
+@startuml
+!include style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor UI_COLOR_T4
+skinparam classBackgroundColor UI_COLOR
+
+package UI <>{
+Class "{abstract}\nUiPart" as UiPart
+Class ControlBox
+Class PopupAddInternship
+Class PopupEditInternship
+Class ApplicationListPanel #CF2765
+Class ApplicationCard
+}
+
+package Model <> {
+Class HiddenModel #FFFFFF
+}
+
+ApplicationListPanel --|> UiPart
+ControlBox --|> UiPart
+PopupAddInternship --|> UiPart
+PopupEditInternship --|> UiPart
+ApplicationCard --|> UiPart
+
+ApplicationListPanel -down-> ControlBox
+ApplicationListPanel -down-> ApplicationCard
+ApplicationCard -down-> PopupEditInternship
+ControlBox -down-> PopupAddInternship
+
+ApplicationCard .right.> Model
+PopupAddInternship .right.> Model
+PopupEditInternship .right.> Model
+
+ApplicationCard -[hidden]right- ControlBox
+
+@enduml
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
index ef81d18c337..8a2382fd5d5 100644
--- a/docs/diagrams/ArchitectureSequenceDiagram.puml
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -13,7 +13,7 @@ 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(i)
activate model MODEL_COLOR
model -[MODEL_COLOR]-> logic
diff --git a/docs/diagrams/ArchiveActivityDiagram.puml b/docs/diagrams/ArchiveActivityDiagram.puml
new file mode 100644
index 00000000000..cc8780ed8c6
--- /dev/null
+++ b/docs/diagrams/ArchiveActivityDiagram.puml
@@ -0,0 +1,17 @@
+@startuml
+start
+:User enters command archive;
+:Generate new ArchiveCommand;
+if () then ([Provided index is valid])
+ if () then ([Internship application is not archived])
+ :Archive the specified application;
+ :Generate success message;
+ else ([else])
+ :Generate error message;
+ endif
+ else ([else])
+ :Generate error message;
+ endif
+:Display result message to user;
+stop
+@enduml
diff --git a/docs/diagrams/ArchiveSequenceDiagram.puml b/docs/diagrams/ArchiveSequenceDiagram.puml
new file mode 100644
index 00000000000..57894cea8bd
--- /dev/null
+++ b/docs/diagrams/ArchiveSequenceDiagram.puml
@@ -0,0 +1,67 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":ArchiveCommandParser" as ArchiveCommandParser LOGIC_COLOR
+participant "a:ArchiveCommand" as ArchiveCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute(archive)
+activate LogicManager
+
+LogicManager -> InternEaseParser : parseCommand(archive)
+activate InternEaseParser
+
+create ArchiveCommandParser
+InternEaseParser -> ArchiveCommandParser
+activate ArchiveCommandParser
+
+ArchiveCommandParser --> InternEaseParser
+deactivate ArchiveCommandParser
+
+InternEaseParser -> ArchiveCommandParser : parse(args)
+activate ArchiveCommandParser
+
+create ArchiveCommand
+ArchiveCommandParser -> ArchiveCommand
+activate ArchiveCommand
+
+ArchiveCommand --> ArchiveCommandParser : a
+deactivate ArchiveCommand
+
+ArchiveCommandParser --> InternEaseParser : a
+deactivate ArchiveCommandParser
+ArchiveCommandParser -[hidden]-> InternEaseParser : result
+destroy ArchiveCommandParser
+
+InternEaseParser --> LogicManager : a
+deactivate InternEaseParser
+
+LogicManager -> ArchiveCommand : execute()
+activate ArchiveCommand
+
+ArchiveCommand -> Model : setApplication(original, archived)
+activate Model
+
+Model --> ArchiveCommand
+deactivate Model
+
+create CommandResult
+ArchiveCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ArchiveCommand : r
+deactivate CommandResult
+
+ArchiveCommand --> LogicManager : r
+deactivate ArchiveCommand
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/ClearByActivityDiagram.puml b/docs/diagrams/ClearByActivityDiagram.puml
new file mode 100644
index 00000000000..29c3bd32561
--- /dev/null
+++ b/docs/diagrams/ClearByActivityDiagram.puml
@@ -0,0 +1,34 @@
+@startuml
+start
+:User enters ClearByCommand;
+if () then ([PREFIX is provided])
+ :Parse command arguments;
+ if () then ([PREFIX is n])
+ :Generate new ClearByCommand of CompanyName;
+ :
+ Refer to activity in Group Company Name
+ ;
+ else ([else])
+ if () then ([PREFIX is j])
+ :Generate new ClearByCommand of JobTitle;
+ :
+ Refer to activity in Group Job Title
+ ;
+ else ([else])
+ if () then ([PREFIX is s])
+ :Generate new ClearByCommand of Status;
+ :
+ Refer to activity in Group Status
+ ;
+ else ([else])
+ :Generate error message;
+ endif
+ endif
+ endif
+ else ([else])
+ :Generate error message;
+endif
+:Display result message to user;
+stop
+
+@enduml
diff --git a/docs/diagrams/ClearBySequenceDiagram.puml b/docs/diagrams/ClearBySequenceDiagram.puml
new file mode 100644
index 00000000000..e3e3fc85574
--- /dev/null
+++ b/docs/diagrams/ClearBySequenceDiagram.puml
@@ -0,0 +1,79 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":ClearByCommandParser" as ClearByCommandParser LOGIC_COLOR
+participant "c:ClearByCommand" as ClearByCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "model:Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute("clear_by pf/ipt")
+activate LogicManager
+
+note right: pf = prefix; ipt = input
+LogicManager -> InternEaseParser : parseCommand("clear_by pf/ipt")
+activate InternEaseParser
+
+create ClearByCommandParser
+InternEaseParser -> ClearByCommandParser
+activate ClearByCommandParser
+
+ClearByCommandParser --> InternEaseParser
+deactivate ClearByCommandParser
+
+InternEaseParser -> ClearByCommandParser : parse("pf/ipt")
+activate ClearByCommandParser
+
+create ClearByCommand
+ClearByCommandParser -> ClearByCommand
+activate ClearByCommand
+
+ClearByCommand --> ClearByCommandParser : c
+deactivate ClearByCommand
+
+ClearByCommandParser --> InternEaseParser : c
+deactivate ClearByCommandParser
+ClearByCommandParser -[hidden]-> InternEaseParser : result
+destroy ClearByCommandParser
+
+InternEaseParser --> LogicManager : c
+deactivate InternEaseParser
+
+LogicManager -> ClearByCommand : execute(model)
+activate ClearByCommand
+
+loop size of filteredList
+
+ClearByCommand -> Model : addInternshipToCache(application)
+activate Model
+
+Model --> ClearByCommand
+deactivate Model
+
+ClearByCommand -> Model : deleteInternship(application)
+activate Model
+
+Model --> ClearByCommand
+deactivate Model
+
+end
+
+create CommandResult
+ClearByCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ClearByCommand : r
+deactivate CommandResult
+
+ClearByCommand --> LogicManager : r
+deactivate ClearByCommand
+
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/ClearSequenceDiagram.puml b/docs/diagrams/ClearSequenceDiagram.puml
new file mode 100644
index 00000000000..fdb268da8c1
--- /dev/null
+++ b/docs/diagrams/ClearSequenceDiagram.puml
@@ -0,0 +1,64 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant "c:ClearCommand" as ClearCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "model:Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute("clear")
+activate LogicManager
+
+LogicManager -> InternEaseParser : parseCommand("clear")
+activate InternEaseParser
+
+create ClearCommand
+InternEaseParser -> ClearCommand
+activate ClearCommand
+
+ClearCommand --> InternEaseParser : c
+deactivate ClearCommand
+
+InternEaseParser --> LogicManager : c
+deactivate InternEaseParser
+
+LogicManager -> ClearCommand : execute(model)
+activate ClearCommand
+
+ClearCommand -> Model : getSortedFilteredInternshipList()
+activate Model
+
+Model --> ClearCommand : lastShownList
+deactivate Model
+
+ClearCommand -> Model : addAllInternshipToCache(lastShownList)
+activate Model
+
+Model --> ClearCommand
+deactivate Model
+
+ClearCommand -> Model : setInternEase(new)
+activate Model
+
+Model --> ClearCommand
+deactivate Model
+
+create CommandResult
+ClearCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ClearCommand : r
+deactivate CommandResult
+
+ClearCommand --> LogicManager : r
+deactivate ClearCommand
+
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/ClearTodoActivityDiagram.puml b/docs/diagrams/ClearTodoActivityDiagram.puml
new file mode 100644
index 00000000000..de710a6595d
--- /dev/null
+++ b/docs/diagrams/ClearTodoActivityDiagram.puml
@@ -0,0 +1,12 @@
+@startuml
+start
+:User enters ClearTodoCommand;
+:Generate new ClearTodoCommand;
+ if () then ([TodoList is empty])
+ :Generate null message;
+ else ([else])
+ :Clear the TodoList and replace it with a new null TodoList;
+ :Generate success message;
+ endif
+stop
+@enduml
diff --git a/docs/diagrams/DeleteContactActivityDiagram.puml b/docs/diagrams/DeleteContactActivityDiagram.puml
new file mode 100644
index 00000000000..a821efa18a8
--- /dev/null
+++ b/docs/diagrams/DeleteContactActivityDiagram.puml
@@ -0,0 +1,13 @@
+@startuml
+start
+:User enters command delete_contact;
+:Generate new DeleteContactCommand;
+if () then ([Provided index is valid])
+ :Delete contact details of the specified application;
+ :Generate success message;
+ else ([else])
+ :Generate error message;
+ endif
+:Display result message to user;
+stop
+@enduml
diff --git a/docs/diagrams/DeleteContactSequenceDiagram.puml b/docs/diagrams/DeleteContactSequenceDiagram.puml
new file mode 100644
index 00000000000..bef0847ce8f
--- /dev/null
+++ b/docs/diagrams/DeleteContactSequenceDiagram.puml
@@ -0,0 +1,75 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":ContactParser" as ContactParser LOGIC_COLOR
+participant ":DeleteContactCommandParser" as DeleteContactCommandParser LOGIC_COLOR
+participant "a:DeleteContactCommand" as DeleteContactCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute(delete_contact)
+activate LogicManager
+
+LogicManager -> InternEaseParser : parseCommand(delete_contact)
+activate InternEaseParser
+
+create ContactParser
+InternEaseParser -> ContactParser : parseContactCommand(delete_contact, args)
+activate ContactParser
+
+create DeleteContactCommandParser
+ContactParser -> DeleteContactCommandParser
+activate DeleteContactCommandParser
+
+DeleteContactCommandParser --> ContactParser
+deactivate DeleteContactCommandParser
+
+ContactParser -> DeleteContactCommandParser : parse(args)
+activate DeleteContactCommandParser
+
+create DeleteContactCommand
+DeleteContactCommandParser -> DeleteContactCommand
+activate DeleteContactCommand
+
+DeleteContactCommand --> DeleteContactCommandParser : d
+deactivate DeleteContactCommand
+
+DeleteContactCommandParser --> ContactParser : d
+deactivate DeleteContactCommandParser
+DeleteContactCommandParser -[hidden]-> InternEaseParser : result
+destroy DeleteContactCommandParser
+
+ContactParser --> InternEaseParser : d
+deactivate ContactParser
+
+InternEaseParser --> LogicManager : d
+deactivate InternEaseParser
+
+LogicManager -> DeleteContactCommand : execute()
+activate DeleteContactCommand
+
+DeleteContactCommand -> Model : setApplication(original, contactDeleted)
+activate Model
+
+Model --> DeleteContactCommand
+deactivate Model
+
+create CommandResult
+DeleteContactCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> DeleteContactCommand : r
+deactivate CommandResult
+
+DeleteContactCommand --> LogicManager : r
+deactivate DeleteContactCommand
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 1dc2311b245..20e1f7b2134 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -3,52 +3,56 @@
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR
-participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR
-participant ":CommandResult" as CommandResult LOGIC_COLOR
+participant "c:DeleteCommand" as DeleteCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
end box
box Model MODEL_COLOR_T1
-participant ":Model" as Model MODEL_COLOR
+participant "model:Model" as Model MODEL_COLOR
end box
-
-[-> LogicManager : execute("delete 1")
+[-> LogicManager : execute("delete INDEX")
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand("delete 1")
-activate AddressBookParser
+LogicManager -> InternEaseParser : parseCommand("delete INDEX")
+activate InternEaseParser
create DeleteCommandParser
-AddressBookParser -> DeleteCommandParser
+InternEaseParser -> DeleteCommandParser
activate DeleteCommandParser
-DeleteCommandParser --> AddressBookParser
+DeleteCommandParser --> InternEaseParser
deactivate DeleteCommandParser
-AddressBookParser -> DeleteCommandParser : parse("1")
+InternEaseParser -> DeleteCommandParser : parse("INDEX")
activate DeleteCommandParser
create DeleteCommand
DeleteCommandParser -> DeleteCommand
activate DeleteCommand
-DeleteCommand --> DeleteCommandParser : d
+DeleteCommand --> DeleteCommandParser : c
deactivate DeleteCommand
-DeleteCommandParser --> AddressBookParser : d
+DeleteCommandParser --> InternEaseParser : c
deactivate DeleteCommandParser
-'Hidden arrow to position the destroy marker below the end of the activation bar.
-DeleteCommandParser -[hidden]-> AddressBookParser
+DeleteCommandParser -[hidden]-> InternEaseParser : result
destroy DeleteCommandParser
-AddressBookParser --> LogicManager : d
-deactivate AddressBookParser
+InternEaseParser --> LogicManager : c
+deactivate InternEaseParser
-LogicManager -> DeleteCommand : execute()
+LogicManager -> DeleteCommand : execute(model)
activate DeleteCommand
-DeleteCommand -> Model : deletePerson(1)
+DeleteCommand -> Model : deleteInternship(internshipToDelete)
+activate Model
+
+Model --> DeleteCommand
+deactivate Model
+
+DeleteCommand -> Model : addInternshipToCache(internshipToDelete)
activate Model
Model --> DeleteCommand
@@ -58,12 +62,13 @@ create CommandResult
DeleteCommand -> CommandResult
activate CommandResult
-CommandResult --> DeleteCommand
+CommandResult --> DeleteCommand : r
deactivate CommandResult
-DeleteCommand --> LogicManager : result
+DeleteCommand --> LogicManager : r
deactivate DeleteCommand
-[<--LogicManager
+
+[<--LogicManager : r
deactivate LogicManager
@enduml
diff --git a/docs/diagrams/DeleteTodoActivityDiagram.puml b/docs/diagrams/DeleteTodoActivityDiagram.puml
new file mode 100644
index 00000000000..9edd18a98a7
--- /dev/null
+++ b/docs/diagrams/DeleteTodoActivityDiagram.puml
@@ -0,0 +1,12 @@
+@startuml
+start
+:User enters DeleteTodoCommand;
+:Generate new DeleteTodoCommand;
+ if () then ([INDEX is valid])
+ :Delete the Todo-task at the specified position;
+ :Generate success message;
+ else ([else])
+ :Generate invalid Index alert message;
+ endif
+stop
+@enduml
diff --git a/docs/diagrams/EditContactActivityDiagram.puml b/docs/diagrams/EditContactActivityDiagram.puml
new file mode 100644
index 00000000000..de1ae309516
--- /dev/null
+++ b/docs/diagrams/EditContactActivityDiagram.puml
@@ -0,0 +1,22 @@
+@startuml
+start
+:User enters command edit_contact;
+if () then ([PREFIX p/ and/or e/ is present])
+ :Parse command arguments;
+ if () then ([Provided argument(s) is/are valid])
+ :Generate new EditContactCommand;
+ if () then ([Provided index is valid])
+ :Edit contact details of the specified application;
+ :Generate success message;
+ else ([else])
+ :Generate error message;
+ endif
+ else ([else])
+ :Generate error message;
+ endif
+ else ([else])
+ :Generate error message;
+endif
+:Display result message to user;
+stop
+@enduml
diff --git a/docs/diagrams/EditContactSequenceDiagram.puml b/docs/diagrams/EditContactSequenceDiagram.puml
new file mode 100644
index 00000000000..fa1c848160c
--- /dev/null
+++ b/docs/diagrams/EditContactSequenceDiagram.puml
@@ -0,0 +1,75 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":ContactParser" as ContactParser LOGIC_COLOR
+participant ":EditContactCommandParser" as EditContactCommandParser LOGIC_COLOR
+participant "a:EditContactCommand" as EditContactCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute(edit_contact)
+activate LogicManager
+
+LogicManager -> InternEaseParser : parseCommand(edit_contact)
+activate InternEaseParser
+
+create ContactParser
+InternEaseParser -> ContactParser : parseContactCommand(edit_contact, args)
+activate ContactParser
+
+create EditContactCommandParser
+ContactParser -> EditContactCommandParser
+activate EditContactCommandParser
+
+EditContactCommandParser --> ContactParser
+deactivate EditContactCommandParser
+
+ContactParser -> EditContactCommandParser : parse(args)
+activate EditContactCommandParser
+
+create EditContactCommand
+EditContactCommandParser -> EditContactCommand
+activate EditContactCommand
+
+EditContactCommand --> EditContactCommandParser : e
+deactivate EditContactCommand
+
+EditContactCommandParser --> ContactParser : e
+deactivate EditContactCommandParser
+EditContactCommandParser -[hidden]-> InternEaseParser : result
+destroy EditContactCommandParser
+
+ContactParser --> InternEaseParser : e
+deactivate ContactParser
+
+InternEaseParser --> LogicManager : e
+deactivate InternEaseParser
+
+LogicManager -> EditContactCommand : execute()
+activate EditContactCommand
+
+EditContactCommand -> Model : setApplication(original, contactEdited)
+activate Model
+
+Model --> EditContactCommand
+deactivate Model
+
+create CommandResult
+EditContactCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> EditContactCommand : r
+deactivate CommandResult
+
+EditContactCommand --> LogicManager : r
+deactivate EditContactCommand
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/EditDeadlineSequenceDiagram.puml b/docs/diagrams/EditDeadlineSequenceDiagram.puml
new file mode 100644
index 00000000000..2f1709f2da3
--- /dev/null
+++ b/docs/diagrams/EditDeadlineSequenceDiagram.puml
@@ -0,0 +1,83 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":TaskParser" as TaskParser LOGIC_COLOR
+participant ":EditDeadlineCommandParser" as EditDeadlineCommandParser LOGIC_COLOR
+participant "c:EditDeadlineCommand" as EditDeadlineCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "model:Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute(input)
+activate LogicManager
+
+note right: input = "edit_deadline 1 by/newDate" \n cmd = "edit_deadline" \n args = "1 by/dt"
+LogicManager -> InternEaseParser : parseCommand(input)
+activate InternEaseParser
+
+InternEaseParser -> TaskParser : parseTaskCommand(cmd, args)
+activate TaskParser
+
+create EditDeadlineCommandParser
+TaskParser -> EditDeadlineCommandParser
+activate EditDeadlineCommandParser
+
+EditDeadlineCommandParser --> TaskParser
+deactivate EditDeadlineCommandParser
+
+TaskParser -> EditDeadlineCommandParser : parse(1, newDate)
+activate EditDeadlineCommandParser
+
+create EditDeadlineCommand
+EditDeadlineCommandParser -> EditDeadlineCommand
+activate EditDeadlineCommand
+
+EditDeadlineCommand --> EditDeadlineCommandParser : c
+deactivate EditDeadlineCommand
+
+EditDeadlineCommandParser --> TaskParser : c
+deactivate EditDeadlineCommandParser
+EditDeadlineCommandParser -[hidden]-> InternEaseParser : result
+destroy EditDeadlineCommandParser
+
+TaskParser --> InternEaseParser : c
+deactivate TaskParser
+
+InternEaseParser --> LogicManager : c
+deactivate InternEaseParser
+
+LogicManager -> EditDeadlineCommand : execute(model)
+activate EditDeadlineCommand
+
+EditDeadlineCommand -> Model : setTodo(original, updated)
+activate Model
+
+Model --> EditDeadlineCommand
+deactivate Model
+
+EditDeadlineCommand -> Model : updateFilteredTodoList()
+activate Model
+
+Model --> EditDeadlineCommand
+deactivate Model
+
+create CommandResult
+EditDeadlineCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> EditDeadlineCommand : r
+deactivate CommandResult
+
+EditDeadlineCommand --> LogicManager : r
+deactivate EditDeadlineCommand
+
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/EditNoteContentSequenceDiagram.puml b/docs/diagrams/EditNoteContentSequenceDiagram.puml
new file mode 100644
index 00000000000..895d66bf6e6
--- /dev/null
+++ b/docs/diagrams/EditNoteContentSequenceDiagram.puml
@@ -0,0 +1,82 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":TaskParser" as TaskParser LOGIC_COLOR
+participant ":EditNoteContentCommandParser" as EditNoteContentCommandParser LOGIC_COLOR
+participant "c:EditNoteContentCommand" as EditNoteContentCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "model:Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute(input)
+activate LogicManager
+
+note right: nc = new content \n input = "edit_content 1 c/nc" \n cmd = "edit_content" , args = "1 c/nc"
+LogicManager -> InternEaseParser : parseCommand(input)
+activate InternEaseParser
+
+InternEaseParser -> TaskParser : parseTaskCommand(cmd, args)
+activate TaskParser
+
+create EditNoteContentCommandParser
+TaskParser -> EditNoteContentCommandParser
+activate EditNoteContentCommandParser
+
+EditNoteContentCommandParser --> TaskParser
+deactivate EditNoteContentCommandParser
+
+TaskParser -> EditNoteContentCommandParser : parse(1, nc)
+activate EditNoteContentCommandParser
+
+create EditNoteContentCommand
+EditNoteContentCommandParser -> EditNoteContentCommand
+activate EditNoteContentCommand
+
+EditNoteContentCommand --> EditNoteContentCommandParser : c
+deactivate EditNoteContentCommand
+
+EditNoteContentCommandParser --> TaskParser : c
+deactivate EditNoteContentCommandParser
+EditNoteContentCommandParser -[hidden]-> InternEaseParser : result
+destroy EditNoteContentCommandParser
+
+TaskParser --> InternEaseParser : c
+deactivate TaskParser
+
+InternEaseParser --> LogicManager : c
+deactivate InternEaseParser
+
+LogicManager -> EditNoteContentCommand : execute(model)
+activate EditNoteContentCommand
+EditNoteContentCommand -> Model : setTodo(original, updated)
+activate Model
+
+Model --> EditNoteContentCommand
+deactivate Model
+
+EditNoteContentCommand -> Model : updateFilteredTodoList()
+activate Model
+
+Model --> EditNoteContentCommand
+deactivate Model
+
+create CommandResult
+EditNoteContentCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> EditNoteContentCommand : r
+deactivate CommandResult
+
+EditNoteContentCommand --> LogicManager : r
+deactivate EditNoteContentCommand
+
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/EditSequenceDiagram.puml b/docs/diagrams/EditSequenceDiagram.puml
new file mode 100644
index 00000000000..48f779dc15b
--- /dev/null
+++ b/docs/diagrams/EditSequenceDiagram.puml
@@ -0,0 +1,62 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":EditCommandParser" as EditCommandParser LOGIC_COLOR
+participant "e:EditCommand" as EditCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute(edit)
+activate LogicManager
+
+LogicManager -> InternEaseParser: parseCommand(edit)
+activate InternEaseParser
+
+create EditCommandParser
+InternEaseParser -> EditCommandParser : EditCommandParser()
+activate EditCommandParser
+
+EditCommandParser --> InternEaseParser
+deactivate EditCommandParser
+
+InternEaseParser -> EditCommandParser : parse(args)
+activate EditCommandParser
+create EditCommand
+EditCommandParser -> EditCommand : EditCommand(index, editInternshipDescriptor)
+activate EditCommand
+
+EditCommand --> EditCommandParser
+deactivate EditCommand
+
+EditCommandParser --> InternEaseParser : e
+deactivate EditCommandParser
+EditCommandParser -[hidden]--> InternEaseParser : e
+destroy EditCommandParser
+
+InternEaseParser --> LogicManager : e
+deactivate InternEaseParser
+
+LogicManager -> EditCommand : execute()
+activate EditCommand
+
+EditCommand -> Model : setApplication(internshipToEdit, editedInternship)
+activate Model
+
+Model --> EditCommand
+deactivate Model
+
+EditCommand --> LogicManager : result
+deactivate EditCommand
+EditCommand -[hidden]--> LogicManager
+destroy EditCommand
+
+<-- LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/EditStatusActivityDiagram.puml b/docs/diagrams/EditStatusActivityDiagram.puml
new file mode 100644
index 00000000000..a96e06ef036
--- /dev/null
+++ b/docs/diagrams/EditStatusActivityDiagram.puml
@@ -0,0 +1,22 @@
+@startuml
+start
+:User enters command edit_status;
+if () then ([PREFIX s/ is present])
+ :Parse command arguments;
+ if () then ([Provided status is valid])
+ :Generate new EditStatusCommand;
+ if () then ([Provided index is valid])
+ :Edit status of the specified application;
+ :Generate success message;
+ else ([else])
+ :Generate error message;
+ endif
+ else ([else])
+ :Generate error message;
+ endif
+ else ([else])
+ :Generate error message;
+endif
+:Display result message to user;
+stop
+@enduml
diff --git a/docs/diagrams/EditStatusSequenceDiagram.puml b/docs/diagrams/EditStatusSequenceDiagram.puml
new file mode 100644
index 00000000000..81d3ddeb68f
--- /dev/null
+++ b/docs/diagrams/EditStatusSequenceDiagram.puml
@@ -0,0 +1,67 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":EditStatusCommandParser" as EditStatusCommandParser LOGIC_COLOR
+participant "a:EditStatusCommand" as EditStatusCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute(edit_contact)
+activate LogicManager
+
+LogicManager -> InternEaseParser : parseCommand(edit_contact)
+activate InternEaseParser
+
+create EditStatusCommandParser
+InternEaseParser -> EditStatusCommandParser
+activate EditStatusCommandParser
+
+EditStatusCommandParser --> InternEaseParser
+deactivate EditStatusCommandParser
+
+InternEaseParser -> EditStatusCommandParser : parse(args)
+activate EditStatusCommandParser
+
+create EditStatusCommand
+EditStatusCommandParser -> EditStatusCommand
+activate EditStatusCommand
+
+EditStatusCommand --> EditStatusCommandParser : e
+deactivate EditStatusCommand
+
+EditStatusCommandParser --> InternEaseParser : e
+deactivate EditStatusCommandParser
+EditStatusCommandParser -[hidden]-> InternEaseParser : result
+destroy EditStatusCommandParser
+
+InternEaseParser --> LogicManager : e
+deactivate InternEaseParser
+
+LogicManager -> EditStatusCommand : execute()
+activate EditStatusCommand
+
+EditStatusCommand -> Model : setApplication(original, statusEdited)
+activate Model
+
+Model --> EditStatusCommand
+deactivate Model
+
+create CommandResult
+EditStatusCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> EditStatusCommand : r
+deactivate CommandResult
+
+EditStatusCommand --> LogicManager : r
+deactivate EditStatusCommand
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/ExitSequenceDiagram.puml b/docs/diagrams/ExitSequenceDiagram.puml
new file mode 100644
index 00000000000..7ad6939b72b
--- /dev/null
+++ b/docs/diagrams/ExitSequenceDiagram.puml
@@ -0,0 +1,42 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant "c:ExitCommand" as ExitCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+[-> LogicManager : execute("exit")
+activate LogicManager
+
+LogicManager -> InternEaseParser : parseCommand("exit")
+activate InternEaseParser
+
+create ExitCommand
+InternEaseParser -> ExitCommand
+activate ExitCommand
+
+ExitCommand --> InternEaseParser : c
+deactivate ExitCommand
+
+InternEaseParser --> LogicManager : c
+deactivate InternEaseParser
+
+LogicManager -> ExitCommand : execute(model)
+activate ExitCommand
+
+create CommandResult
+ExitCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ExitCommand : r
+deactivate CommandResult
+
+ExitCommand --> LogicManager : r
+deactivate ExitCommand
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/FindFeatureClassDiagram.puml b/docs/diagrams/FindFeatureClassDiagram.puml
new file mode 100644
index 00000000000..a43aaa6c5f5
--- /dev/null
+++ b/docs/diagrams/FindFeatureClassDiagram.puml
@@ -0,0 +1,42 @@
+@startuml
+!include style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor LOGIC_COLOR_T4
+skinparam classBackgroundColor LOGIC_COLOR
+
+package Logic {
+
+Class FindCommandParser
+Class FindCommand
+Class FindStatusCommand
+Class FindDateCommand
+Class "{abstract}\nCommand" as Command
+}
+
+package Model{
+
+Class NameContainsKeywordsPredicate MODEL_COLOR
+Class StatusPredicate MODEL_COLOR
+Class "{abstract}\nDatePredicate" as DatePredicate MODEL_COLOR
+Class BeforeDatePredicate MODEL_COLOR
+Class AfterDatePredicate MODEL_COLOR
+Class BetweenDatePredicate MODEL_COLOR
+}
+
+FindCommand -up-|> Command
+FindDateCommand -up[LOGIC_COLOR_T4]-|> FindCommand
+FindStatusCommand -up[LOGIC_COLOR_T4]-|> FindCommand
+FindCommandParser .up.> FindCommand
+FindCommandParser .up.> FindDateCommand
+FindCommandParser .up.> FindStatusCommand
+
+BeforeDatePredicate -up[MODEL_COLOR]--|> DatePredicate
+AfterDatePredicate -up[MODEL_COLOR]--|> DatePredicate
+BetweenDatePredicate --up[MODEL_COLOR]--|> DatePredicate
+
+FindCommand -left->"1" NameContainsKeywordsPredicate
+FindDateCommand -left->"1" DatePredicate
+FindStatusCommand -left->"1" StatusPredicate
+
+Command ..> Model
+@enduml
diff --git a/docs/diagrams/FindSequenceDiagram.puml b/docs/diagrams/FindSequenceDiagram.puml
new file mode 100644
index 00000000000..9e689c8eb6f
--- /dev/null
+++ b/docs/diagrams/FindSequenceDiagram.puml
@@ -0,0 +1,77 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":FindCommandParser" as FindCommandParser LOGIC_COLOR
+participant "p:NameContainsKeywordsPredicate" as NameContainsKeywordsPredicate LOGIC_COLOR
+participant "f:FindCommand" as FindCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("find google")
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("find google")
+activate AddressBookParser
+
+create FindCommandParser
+AddressBookParser -> FindCommandParser
+activate FindCommandParser
+
+FindCommandParser --> AddressBookParser
+deactivate FindCommandParser
+
+AddressBookParser -> FindCommandParser : parse("google")
+activate FindCommandParser
+
+create NameContainsKeywordsPredicate
+FindCommandParser -> NameContainsKeywordsPredicate
+activate NameContainsKeywordsPredicate
+
+NameContainsKeywordsPredicate --> FindCommandParser
+deactivate NameContainsKeywordsPredicate
+
+create FindCommand
+FindCommandParser -> FindCommand : FindCommand(p)
+activate FindCommand
+
+FindCommand --> FindCommandParser : f
+deactivate FindCommand
+
+FindCommandParser --> AddressBookParser : f
+deactivate FindCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+FindCommandParser -[hidden]-> AddressBookParser
+destroy FindCommandParser
+
+AddressBookParser --> LogicManager : f
+deactivate AddressBookParser
+
+LogicManager -> FindCommand : execute()
+activate FindCommand
+
+FindCommand -> Model : updateFilteredInternshipList(p)
+activate Model
+
+Model --> FindCommand
+deactivate Model
+
+create CommandResult
+FindCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> FindCommand
+deactivate CommandResult
+
+FindCommand --> LogicManager : result
+deactivate FindCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/FindTaskSequenceDiagram.puml b/docs/diagrams/FindTaskSequenceDiagram.puml
new file mode 100644
index 00000000000..85596d38937
--- /dev/null
+++ b/docs/diagrams/FindTaskSequenceDiagram.puml
@@ -0,0 +1,83 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant ":TaskParser" as TaskParser LOGIC_COLOR
+participant ":FindTaskCommandParser" as FindTaskCommandParser LOGIC_COLOR
+participant "c:FindTaskCommand" as FindTaskCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "model:Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute(input)
+activate LogicManager
+
+note right: kw = keyword \n input = "find_task kw" \n cmd = "find_task"
+LogicManager -> InternEaseParser : parseCommand(input)
+activate InternEaseParser
+
+InternEaseParser -> TaskParser : parseTaskCommand(cmd, kw)
+activate TaskParser
+
+create FindTaskCommandParser
+TaskParser -> FindTaskCommandParser
+activate FindTaskCommandParser
+
+FindTaskCommandParser --> TaskParser
+deactivate FindTaskCommandParser
+
+TaskParser -> FindTaskCommandParser : parse("kw")
+activate FindTaskCommandParser
+
+create FindTaskCommand
+FindTaskCommandParser -> FindTaskCommand
+activate FindTaskCommand
+
+FindTaskCommand --> FindTaskCommandParser : c
+deactivate FindTaskCommand
+
+FindTaskCommandParser --> TaskParser : c
+deactivate FindTaskCommandParser
+FindTaskCommandParser -[hidden]-> InternEaseParser : result
+destroy FindTaskCommandParser
+
+TaskParser --> InternEaseParser : c
+deactivate TaskParser
+
+InternEaseParser --> LogicManager : c
+deactivate InternEaseParser
+
+LogicManager -> FindTaskCommand : execute(model)
+activate FindTaskCommand
+
+FindTaskCommand -> Model : updateFilteredTodoList()
+activate Model
+
+Model --> FindTaskCommand
+deactivate Model
+
+FindTaskCommand -> Model : updateFilteredNoteList()
+activate Model
+
+Model --> FindTaskCommand
+deactivate Model
+
+create CommandResult
+FindTaskCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> FindTaskCommand : r
+deactivate CommandResult
+
+FindTaskCommand --> LogicManager : r
+deactivate FindTaskCommand
+
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/GroupCompanyName.puml b/docs/diagrams/GroupCompanyName.puml
new file mode 100644
index 00000000000..d558d082a92
--- /dev/null
+++ b/docs/diagrams/GroupCompanyName.puml
@@ -0,0 +1,10 @@
+@startuml
+start
+if () then ([Internship application list is empty])
+:Generate null list message;
+else ([else])
+:Clear all internship applications with keyword for COMPANY_NAME;
+:Generate success message;
+endif
+stop
+@enduml
diff --git a/docs/diagrams/GroupJobTitle.puml b/docs/diagrams/GroupJobTitle.puml
new file mode 100644
index 00000000000..3a5b6cf414a
--- /dev/null
+++ b/docs/diagrams/GroupJobTitle.puml
@@ -0,0 +1,10 @@
+@startuml
+start
+if () then ([Internship application list is empty])
+:Generate null list message;
+else ([else])
+:Clear all internship applications with keyword for JOB_TITLE;
+:Generate success message;
+endif
+stop
+@enduml
diff --git a/docs/diagrams/GroupStatus.puml b/docs/diagrams/GroupStatus.puml
new file mode 100644
index 00000000000..c0cf0b8280c
--- /dev/null
+++ b/docs/diagrams/GroupStatus.puml
@@ -0,0 +1,10 @@
+@startuml
+start
+if () then ([Internship application list is empty])
+:Generate null list message;
+else ([else])
+:Clear all internship applications with keyword for STATUS;
+:Generate success message;
+endif
+stop
+@enduml
diff --git a/docs/diagrams/ListActivityDiagram.puml b/docs/diagrams/ListActivityDiagram.puml
new file mode 100644
index 00000000000..627fe8df166
--- /dev/null
+++ b/docs/diagrams/ListActivityDiagram.puml
@@ -0,0 +1,13 @@
+@startuml
+start
+:User enters command list;
+:Generate new ListCommand;
+:Update the list filteredInternshipList to show all ongoing applications;
+ if () then ([filteredInternshipList is not empty])
+ :Generate success message;
+ else ([else])
+ :Generate no active applications message;
+ endif
+stop
+
+@enduml
diff --git a/docs/diagrams/ListArchivedActivityDiagram.puml b/docs/diagrams/ListArchivedActivityDiagram.puml
new file mode 100644
index 00000000000..533fdd8ed8b
--- /dev/null
+++ b/docs/diagrams/ListArchivedActivityDiagram.puml
@@ -0,0 +1,13 @@
+@startuml
+start
+:User enters command list_archived;
+:Generate new ListArchivedCommand;
+:Update the list filteredInternships to show only archived entries;
+ if () then ([filteredInternships is not empty])
+ :Generate success message;
+ else ([else])
+ :Generate error message;
+ endif
+stop
+
+@enduml
diff --git a/docs/diagrams/ListTaskActivityDiagram.puml b/docs/diagrams/ListTaskActivityDiagram.puml
new file mode 100644
index 00000000000..c50c5c9a4fc
--- /dev/null
+++ b/docs/diagrams/ListTaskActivityDiagram.puml
@@ -0,0 +1,13 @@
+@startuml
+start
+:User enters ListTaskCommand;
+:Generate new ListTaskCommand;
+:Update filtered TodoList and filtered NoteList to show all entries;
+ if () then ([TodoList and NoteList are both empty])
+ :Generate null message;
+ else ([else])
+ :Generate success message;
+ endif
+stop
+
+@enduml
diff --git a/docs/diagrams/ListTodoActivityDiagram.puml b/docs/diagrams/ListTodoActivityDiagram.puml
new file mode 100644
index 00000000000..05ad20efede
--- /dev/null
+++ b/docs/diagrams/ListTodoActivityDiagram.puml
@@ -0,0 +1,13 @@
+@startuml
+start
+:User enters ListTodoCommand;
+:Generate new ListTodoCommand;
+:Update filtered TodoList to show all entries;
+ if () then ([TodoList is empty])
+ :Generate null message;
+ else ([else])
+ :Generate success message;
+ endif
+stop
+
+@enduml
diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml
index d4193173e18..05e1971b618 100644
--- a/docs/diagrams/LogicClassDiagram.puml
+++ b/docs/diagrams/LogicClassDiagram.puml
@@ -6,7 +6,7 @@ skinparam classBackgroundColor LOGIC_COLOR
package Logic {
-Class AddressBookParser
+Class InternEaseParser
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" InternEaseParser
+InternEaseParser ..> XYZCommand : creates >
XYZCommand -up-|> Command
LogicManager .left.> Command : executes >
diff --git a/docs/diagrams/MixedPanelRef.puml b/docs/diagrams/MixedPanelRef.puml
new file mode 100644
index 00000000000..ae96c8afd18
--- /dev/null
+++ b/docs/diagrams/MixedPanelRef.puml
@@ -0,0 +1,35 @@
+@startuml
+!include style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor UI_COLOR_T4
+skinparam classBackgroundColor UI_COLOR
+
+package UI <>{
+Class "{abstract}\nUiPart" as UiPart
+Class TodoListPanel
+Class NoteListPanel
+Class MixedPanel #CF2765
+Class TodoCard
+Class NoteCard
+}
+
+package Model <> {
+Class HiddenModel #FFFFFF
+}
+
+MixedPanel --|> UiPart
+TodoListPanel --|> UiPart
+NoteListPanel --|> UiPart
+TodoCard --|> UiPart
+NoteCard --|> UiPart
+
+MixedPanel -down-> "1" TodoListPanel
+MixedPanel -down-> "1" NoteListPanel
+TodoListPanel -down-> TodoCard
+NoteListPanel -down-> NoteCard
+
+TodoCard .right.> Model
+NoteCard .right.> Model
+NoteCard -[hidden]right- TodoCard
+
+@enduml
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 4439108973a..aedb39a9b79 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -4,7 +4,7 @@ skinparam arrowThickness 1.1
skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
-Package Model <>{
+Package "Model classes" <>{
Class "<>\nReadOnlyAddressBook" as ReadOnlyAddressBook
Class "<>\nReadOnlyUserPrefs" as ReadOnlyUserPrefs
Class "<>\nModel" as Model
@@ -12,13 +12,22 @@ Class AddressBook
Class ModelManager
Class UserPrefs
-Class UniquePersonList
-Class Person
-Class Address
-Class Email
-Class Name
-Class Phone
-Class Tag
+Class UniqueApplicationList
+Class InternshipApplication
+Class CompanyName
+Class JobTitle
+Class Review
+Class ProgrammingLanguage
+Class Qualification
+Class Location
+Class Salary
+Class Note
+Class Rating
+Class Reflection
+Class InterviewDate
+Class InternshipStatus
+Class Contact
+Class Documents
}
@@ -34,17 +43,22 @@ ModelManager -left-> "1" AddressBook
ModelManager -right-> "1" UserPrefs
UserPrefs .up.|> ReadOnlyUserPrefs
-AddressBook *--> "1" UniquePersonList
-UniquePersonList --> "~* all" Person
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-Person *--> "*" Tag
+AddressBook *--> "1" UniqueApplicationList
+UniqueApplicationList --> "~* all" InternshipApplication
+InternshipApplication *--> CompanyName
+InternshipApplication *--> JobTitle
+InternshipApplication *--> "*" Review
+InternshipApplication *--> "*" ProgrammingLanguage
+InternshipApplication *--> "*" Qualification
+InternshipApplication *--> Location
+InternshipApplication *--> Salary
+InternshipApplication *--> "*" Note
+InternshipApplication *--> Rating
+InternshipApplication *--> "*" Reflection
+InternshipApplication *--> InterviewDate
+InternshipApplication *--> InternshipStatus
+InternshipApplication *--> Contact
+InternshipApplication *--> Documents
-Name -[hidden]right-> Phone
-Phone -[hidden]right-> Address
-Address -[hidden]right-> Email
-
-ModelManager -->"~* filtered" Person
+ModelManager -->"~* filtered" InternshipApplication
@enduml
diff --git a/docs/diagrams/NoteOverviewDiagram.puml b/docs/diagrams/NoteOverviewDiagram.puml
new file mode 100644
index 00000000000..59b16b290dd
--- /dev/null
+++ b/docs/diagrams/NoteOverviewDiagram.puml
@@ -0,0 +1,49 @@
+@startuml
+!include style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor LOGIC_COLOR_T4
+skinparam classBackgroundColor LOGIC_COLOR
+
+package Logic {
+
+Class AddNoteCommandParser
+Class DeleteNoteCommandParser
+Class AddNoteCommand
+Class ClearNoteCommand
+Class DeleteNoteCommand
+Class ListNoteCommand
+Class "{abstract}\nCommand" as Command
+}
+
+package Model{
+
+Class NoteList MODEL_COLOR
+Class UniqueNoteList MODEL_COLOR
+Class "{abstract}\nReadOnlyNoteList" as ReadOnlyNoteList MODEL_COLOR
+Class Note MODEL_COLOR
+Class NoteContent MODEL_COLOR
+Class "<>\nTaskType" as TaskType MODEL_COLOR
+}
+
+AddNoteCommand -up-|> Command
+ClearNoteCommand -up-|> Command
+DeleteNoteCommand -up-|> Command
+ListNoteCommand -up-|> Command
+AddNoteCommandParser .up.> AddNoteCommand
+DeleteNoteCommandParser .up.> DeleteNoteCommand
+
+AddNoteCommand .up.> NoteList
+ClearNoteCommand .up.> NoteList
+DeleteNoteCommand .up.> NoteList
+ListNoteCommand .up.> NoteList
+
+NoteList -up-|> ReadOnlyNoteList
+NoteList *--> UniqueNoteList
+NoteList *--> Note
+Note *--> NoteContent
+Note *--> TaskType
+
+AddNoteCommand -left->"1" Note
+
+Command ..> Model
+@enduml
diff --git a/docs/diagrams/PanelsRef.puml b/docs/diagrams/PanelsRef.puml
new file mode 100644
index 00000000000..f8facf5e17c
--- /dev/null
+++ b/docs/diagrams/PanelsRef.puml
@@ -0,0 +1,36 @@
+@startuml
+!include style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor UI_COLOR_T4
+skinparam classBackgroundColor UI_COLOR
+
+package Model <> {
+Class HiddenModel #FFFFFF
+}
+
+package Panels <> {
+Class "{abstract}\nUiPart" as UiPart
+Class MixedPanel #CF2765
+Class ApplicationListPanel #CF2765
+Class StatsInformationListPanel #CF2765
+Class StatsInformationCard #CF2765
+Class ViewContentPanel #CF2765
+Class MainWindow
+}
+
+MainWindow *-down-> "1" ApplicationListPanel
+MainWindow *-down-> "1" StatsInformationListPanel
+MainWindow *-down-> "1" MixedPanel
+MainWindow *-down-> "1" ViewContentPanel
+
+MixedPanel --|> UiPart
+ApplicationListPanel --|> UiPart
+StatsInformationListPanel --|> UiPart
+StatsInformationCard --|> UiPart
+ViewContentPanel --|> UiPart
+
+StatsInformationListPanel -down-> StatsInformationCard
+
+StatsInformationCard .right.> Model
+
+@enduml
diff --git a/docs/diagrams/ParserClasses.puml b/docs/diagrams/ParserClasses.puml
index 0c7424de6e0..79e6f70aa39 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 InternEaseParser
Class XYZCommandParser
Class CliSyntax
Class ParserUtil
@@ -19,12 +19,12 @@ Class Prefix
}
Class HiddenOutside #FFFFFF
-HiddenOutside ..> AddressBookParser
+HiddenOutside ..> InternEaseParser
-AddressBookParser .down.> XYZCommandParser: creates >
+InternEaseParser .down.> XYZCommandParser: creates >
XYZCommandParser ..> XYZCommand : creates >
-AddressBookParser ..> Command : returns >
+InternEaseParser ..> Command : returns >
XYZCommandParser .up.|> Parser
XYZCommandParser ..> ArgumentMultimap
XYZCommandParser ..> ArgumentTokenizer
diff --git a/docs/diagrams/RevertActivityDiagram.puml b/docs/diagrams/RevertActivityDiagram.puml
new file mode 100644
index 00000000000..f8019ed257d
--- /dev/null
+++ b/docs/diagrams/RevertActivityDiagram.puml
@@ -0,0 +1,17 @@
+@startuml
+start
+:User enters RevertCommand;
+:Generate new RevertCommand;
+ if () then ([CacheList is not empty])
+ :Remove the most recent deleted application from the cacheList;
+ if () then ([The retrieved application is not in current application list])
+ :Add the retrieved application to the end of the current application list;
+ else ([else])
+ :Generate duplicate internship applications alert;
+ endif
+ else ([else])
+ :Generate null cacheList message;
+ endif
+stop
+
+@enduml
diff --git a/docs/diagrams/RevertAllSequenceDiagram.puml b/docs/diagrams/RevertAllSequenceDiagram.puml
new file mode 100644
index 00000000000..dc38a56c440
--- /dev/null
+++ b/docs/diagrams/RevertAllSequenceDiagram.puml
@@ -0,0 +1,64 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternEaseParser" as InternEaseParser LOGIC_COLOR
+participant "c:RevertAllCommand" as RevertAllCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "model:Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("clear")
+activate LogicManager
+
+LogicManager -> InternEaseParser : parseCommand("clear")
+activate InternEaseParser
+
+create RevertAllCommand
+InternEaseParser -> RevertAllCommand
+activate RevertAllCommand
+
+RevertAllCommand --> InternEaseParser : c
+deactivate RevertAllCommand
+
+InternEaseParser --> LogicManager : c
+deactivate InternEaseParser
+
+LogicManager -> RevertAllCommand : execute(model)
+activate RevertAllCommand
+
+RevertAllCommand -> Model : getCachedInternshipList()
+activate Model
+
+Model --> RevertAllCommand : cacheList
+deactivate Model
+
+RevertAllCommand -> Model : setEmptyInternshipCacheList()
+activate Model
+
+Model --> RevertAllCommand
+deactivate Model
+
+RevertAllCommand -> Model : addApplications(cacheList)
+activate Model
+
+Model --> RevertAllCommand
+deactivate Model
+
+create CommandResult
+RevertAllCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> RevertAllCommand : r
+deactivate CommandResult
+
+RevertAllCommand --> LogicManager : r
+deactivate RevertAllCommand
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/SortSequenceDiagram.puml b/docs/diagrams/SortSequenceDiagram.puml
new file mode 100644
index 00000000000..031177fccce
--- /dev/null
+++ b/docs/diagrams/SortSequenceDiagram.puml
@@ -0,0 +1,82 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":SortCommandParser" as SortCommandParser LOGIC_COLOR
+participant "cmp:InterviewDateComparator" as InterviewDateComparator LOGIC_COLOR
+participant "s:SortCommand" as SortCommand LOGIC_COLOR
+participant "result:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("sort d/")
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("sort d/")
+activate AddressBookParser
+
+create SortCommandParser
+AddressBookParser -> SortCommandParser
+activate SortCommandParser
+
+SortCommandParser --> AddressBookParser
+deactivate SortCommandParser
+
+AddressBookParser -> SortCommandParser : parse("d/")
+activate SortCommandParser
+
+create InterviewDateComparator
+SortCommandParser -> InterviewDateComparator
+activate InterviewDateComparator
+
+InterviewDateComparator --> SortCommandParser
+deactivate InterviewDateComparator
+
+create SortCommand
+SortCommandParser -> SortCommand : SortCommand(cmp)
+activate SortCommand
+
+SortCommand --> SortCommandParser : s
+deactivate SortCommand
+
+SortCommandParser --> AddressBookParser : s
+deactivate SortCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+SortCommandParser -[hidden]-> AddressBookParser
+destroy SortCommandParser
+
+AddressBookParser --> LogicManager : s
+deactivate AddressBookParser
+
+LogicManager -> SortCommand : execute()
+activate SortCommand
+
+SortCommand -> Model : updateSortedFilteredInternshipList(cmp)
+activate Model
+
+Model --> SortCommand
+deactivate Model
+
+create CommandResult
+SortCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> SortCommand
+deactivate CommandResult
+
+SortCommand --> LogicManager : result
+deactivate SortCommand
+
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+SortCommand -[hidden]-> LogicManager
+destroy SortCommand
+
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index 760305e0e58..ad6371432ca 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -4,7 +4,7 @@ skinparam arrowThickness 1.1
skinparam arrowColor STORAGE_COLOR
skinparam classBackgroundColor STORAGE_COLOR
-package Storage{
+package "Storage classes" {
package "UserPrefs Storage" #F4F6F6{
Class "<>\nUserPrefsStorage" as UserPrefsStorage
@@ -18,8 +18,7 @@ package "AddressBook Storage" #F4F6F6{
Class "<>\nAddressBookStorage" as AddressBookStorage
Class JsonAddressBookStorage
Class JsonSerializableAddressBook
-Class JsonAdaptedPerson
-Class JsonAdaptedTag
+Class JsonAdaptedInternshipApplication
}
}
@@ -37,7 +36,6 @@ Storage -right-|> AddressBookStorage
JsonUserPrefsStorage .up.|> UserPrefsStorage
JsonAddressBookStorage .up.|> AddressBookStorage
JsonAddressBookStorage ..> JsonSerializableAddressBook
-JsonSerializableAddressBook --> "*" JsonAdaptedPerson
-JsonAdaptedPerson --> "*" JsonAdaptedTag
+JsonSerializableAddressBook --> "*" JsonAdaptedInternshipApplication
@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 95473d5aa19..b2561abb166 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -10,15 +10,13 @@ Class "{abstract}\nUiPart" as UiPart
Class UiManager
Class MainWindow
Class HelpWindow
-Class ResultDisplay
-Class PersonListPanel
-Class PersonCard
-Class StatusBarFooter
+Class ReminderWindow
Class CommandBox
-}
-
-package Model <> {
-Class HiddenModel #FFFFFF
+Class ResultDialog
+Class Panels #CF2765
+Class QuickAccessToolbar
+Class PopupAddInternship
+Class PopupEditInternship
}
package Logic <> {
@@ -31,30 +29,31 @@ HiddenOutside ..> Ui
UiManager .left.|> Ui
UiManager -down-> "1" MainWindow
MainWindow *-down-> "1" CommandBox
-MainWindow *-down-> "1" ResultDisplay
-MainWindow *-down-> "1" PersonListPanel
-MainWindow *-down-> "1" StatusBarFooter
-MainWindow --> "0..1" HelpWindow
-
-PersonListPanel -down-> "*" PersonCard
-
-MainWindow -left-|> UiPart
-
-ResultDisplay --|> UiPart
+MainWindow *-down-> HelpWindow
+MainWindow *-down-> ReminderWindow
+MainWindow --> "0..1" ResultDialog
+MainWindow *-down-> "1" Panels
+MainWindow *-down-> "1" QuickAccessToolbar
+MainWindow *-down-> "1" PopupAddInternship
+MainWindow *-down-> "*" PopupEditInternship
+
+MainWindow --|> UiPart
CommandBox --|> UiPart
-PersonListPanel --|> UiPart
-PersonCard --|> UiPart
-StatusBarFooter --|> UiPart
HelpWindow --|> UiPart
+ReminderWindow --|> UiPart
+Panels --|> UiPart
+QuickAccessToolbar --|> UiPart
+PopupAddInternship --|> UiPart
+PopupEditInternship --|> UiPart
-PersonCard ..> Model
-UiManager -right-> Logic
+UiManager -left-> Logic
MainWindow -left-> Logic
-PersonListPanel -[hidden]left- HelpWindow
-HelpWindow -[hidden]left- CommandBox
-CommandBox -[hidden]left- ResultDisplay
-ResultDisplay -[hidden]left- StatusBarFooter
+HelpWindow -[hidden]right- ResultDialog
+ResultDialog -[hidden]right- CommandBox
+CommandBox -[hidden]right- Panels
+MainWindow -[hidden]right- QuickAccessToolbar
+UiManager -[hidden]down- Logic
MainWindow -[hidden]-|> UiPart
@enduml
diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/UndoRedoState0.puml
index 96e30744d24..34885420931 100644
--- a/docs/diagrams/UndoRedoState0.puml
+++ b/docs/diagrams/UndoRedoState0.puml
@@ -15,6 +15,6 @@ State2 -[hidden]right-> State3
hide State2
hide State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State1
@end
diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml
index bccc230a5d1..0ce7073e187 100644
--- a/docs/diagrams/UndoRedoState2.puml
+++ b/docs/diagrams/UndoRedoState2.puml
@@ -14,7 +14,7 @@ package States <> {
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State3
@end
diff --git a/docs/diagrams/UndoSequenceDiagram.puml b/docs/diagrams/UndoSequenceDiagram.puml
deleted file mode 100644
index 410aab4e412..00000000000
--- a/docs/diagrams/UndoSequenceDiagram.puml
+++ /dev/null
@@ -1,53 +0,0 @@
-@startuml
-!include style.puml
-
-box Logic LOGIC_COLOR_T1
-participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser 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
-end box
-[-> LogicManager : execute(undo)
-activate LogicManager
-
-LogicManager -> AddressBookParser : parseCommand(undo)
-activate AddressBookParser
-
-create UndoCommand
-AddressBookParser -> UndoCommand
-activate UndoCommand
-
-UndoCommand --> AddressBookParser
-deactivate UndoCommand
-
-AddressBookParser --> LogicManager : u
-deactivate AddressBookParser
-
-LogicManager -> UndoCommand : execute()
-activate UndoCommand
-
-UndoCommand -> Model : undoAddressBook()
-activate Model
-
-Model -> VersionedAddressBook : undo()
-activate VersionedAddressBook
-
-VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook)
-VersionedAddressBook --> Model :
-deactivate VersionedAddressBook
-
-Model --> UndoCommand
-deactivate Model
-
-UndoCommand --> LogicManager : result
-deactivate UndoCommand
-UndoCommand -[hidden]-> LogicManager : result
-destroy UndoCommand
-
-[<--LogicManager
-deactivate LogicManager
-@enduml
diff --git a/docs/images/AddContactActivityDiagram.png b/docs/images/AddContactActivityDiagram.png
new file mode 100644
index 00000000000..442d0d04956
Binary files /dev/null and b/docs/images/AddContactActivityDiagram.png differ
diff --git a/docs/images/AddContactSequenceDiagram.png b/docs/images/AddContactSequenceDiagram.png
new file mode 100644
index 00000000000..89292794f95
Binary files /dev/null and b/docs/images/AddContactSequenceDiagram.png differ
diff --git a/docs/images/AddDocumentsActivityDiagram.png b/docs/images/AddDocumentsActivityDiagram.png
new file mode 100644
index 00000000000..b343c869a11
Binary files /dev/null and b/docs/images/AddDocumentsActivityDiagram.png differ
diff --git a/docs/images/AddDocumentsSequenceDiagram.png b/docs/images/AddDocumentsSequenceDiagram.png
new file mode 100644
index 00000000000..fa5bf23f640
Binary files /dev/null and b/docs/images/AddDocumentsSequenceDiagram.png differ
diff --git a/docs/images/AddSequenceDiagram.png b/docs/images/AddSequenceDiagram.png
new file mode 100644
index 00000000000..53cdad1eed3
Binary files /dev/null and b/docs/images/AddSequenceDiagram.png differ
diff --git a/docs/images/AddTodoActivityDiagram.png b/docs/images/AddTodoActivityDiagram.png
new file mode 100644
index 00000000000..0256286c99a
Binary files /dev/null and b/docs/images/AddTodoActivityDiagram.png differ
diff --git a/docs/images/ApplicationListPanelRef.png b/docs/images/ApplicationListPanelRef.png
new file mode 100644
index 00000000000..dc8c9d9d35b
Binary files /dev/null and b/docs/images/ApplicationListPanelRef.png differ
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
index 2f1346869d0..4a47cb2ec2b 100644
Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ
diff --git a/docs/images/ArchiveActivityDiagram.png b/docs/images/ArchiveActivityDiagram.png
new file mode 100644
index 00000000000..2596e4db053
Binary files /dev/null and b/docs/images/ArchiveActivityDiagram.png differ
diff --git a/docs/images/ArchiveSequenceDiagram.png b/docs/images/ArchiveSequenceDiagram.png
new file mode 100644
index 00000000000..c6a03b35019
Binary files /dev/null and b/docs/images/ArchiveSequenceDiagram.png differ
diff --git a/docs/images/ClearByActivityDiagram.png b/docs/images/ClearByActivityDiagram.png
new file mode 100644
index 00000000000..9e39fc93675
Binary files /dev/null and b/docs/images/ClearByActivityDiagram.png differ
diff --git a/docs/images/ClearBySequenceDiagram.png b/docs/images/ClearBySequenceDiagram.png
new file mode 100644
index 00000000000..b9e3c54f888
Binary files /dev/null and b/docs/images/ClearBySequenceDiagram.png differ
diff --git a/docs/images/ClearSequenceDiagram.png b/docs/images/ClearSequenceDiagram.png
new file mode 100644
index 00000000000..9a2b9575b45
Binary files /dev/null and b/docs/images/ClearSequenceDiagram.png differ
diff --git a/docs/images/ClearTodoActivityDiagram.png b/docs/images/ClearTodoActivityDiagram.png
new file mode 100644
index 00000000000..c654dea169f
Binary files /dev/null and b/docs/images/ClearTodoActivityDiagram.png differ
diff --git a/docs/images/DeleteContactActivityDiagram.png b/docs/images/DeleteContactActivityDiagram.png
new file mode 100644
index 00000000000..1c446ef2209
Binary files /dev/null and b/docs/images/DeleteContactActivityDiagram.png differ
diff --git a/docs/images/DeleteContactSequenceDiagram.png b/docs/images/DeleteContactSequenceDiagram.png
new file mode 100644
index 00000000000..eeb4c4fd680
Binary files /dev/null and b/docs/images/DeleteContactSequenceDiagram.png differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
index fa327b39618..affbe8d9dab 100644
Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ
diff --git a/docs/images/DeleteTodoActivityDiagram.png b/docs/images/DeleteTodoActivityDiagram.png
new file mode 100644
index 00000000000..44cb22a608e
Binary files /dev/null and b/docs/images/DeleteTodoActivityDiagram.png differ
diff --git a/docs/images/EditContactActivityDiagram.png b/docs/images/EditContactActivityDiagram.png
new file mode 100644
index 00000000000..9adefd799e9
Binary files /dev/null and b/docs/images/EditContactActivityDiagram.png differ
diff --git a/docs/images/EditContactSequenceDiagram.png b/docs/images/EditContactSequenceDiagram.png
new file mode 100644
index 00000000000..44be7a8cdb5
Binary files /dev/null and b/docs/images/EditContactSequenceDiagram.png differ
diff --git a/docs/images/EditDeadlineSequenceDiagram.png b/docs/images/EditDeadlineSequenceDiagram.png
new file mode 100644
index 00000000000..ce55b2b1f22
Binary files /dev/null and b/docs/images/EditDeadlineSequenceDiagram.png differ
diff --git a/docs/images/EditNoteContentSequenceDiagram.png b/docs/images/EditNoteContentSequenceDiagram.png
new file mode 100644
index 00000000000..8b37971494e
Binary files /dev/null and b/docs/images/EditNoteContentSequenceDiagram.png differ
diff --git a/docs/images/EditSequenceDiagram.png b/docs/images/EditSequenceDiagram.png
new file mode 100644
index 00000000000..0414e0fb469
Binary files /dev/null and b/docs/images/EditSequenceDiagram.png differ
diff --git a/docs/images/EditStatusActivityDiagram.png b/docs/images/EditStatusActivityDiagram.png
new file mode 100644
index 00000000000..17cde8f1cc7
Binary files /dev/null and b/docs/images/EditStatusActivityDiagram.png differ
diff --git a/docs/images/EditStatusSequenceDiagram.png b/docs/images/EditStatusSequenceDiagram.png
new file mode 100644
index 00000000000..d33b3c00dce
Binary files /dev/null and b/docs/images/EditStatusSequenceDiagram.png differ
diff --git a/docs/images/ExitSequenceDiagram.png b/docs/images/ExitSequenceDiagram.png
new file mode 100644
index 00000000000..b51245fb414
Binary files /dev/null and b/docs/images/ExitSequenceDiagram.png differ
diff --git a/docs/images/FindFeatureClassDiagram.png b/docs/images/FindFeatureClassDiagram.png
new file mode 100644
index 00000000000..d2503276cde
Binary files /dev/null and b/docs/images/FindFeatureClassDiagram.png differ
diff --git a/docs/images/FindSequenceDiagram.png b/docs/images/FindSequenceDiagram.png
new file mode 100644
index 00000000000..da882014681
Binary files /dev/null and b/docs/images/FindSequenceDiagram.png differ
diff --git a/docs/images/FindTaskSequenceDiagram.png b/docs/images/FindTaskSequenceDiagram.png
new file mode 100644
index 00000000000..48b71706871
Binary files /dev/null and b/docs/images/FindTaskSequenceDiagram.png differ
diff --git a/docs/images/GroupCompanyName.png b/docs/images/GroupCompanyName.png
new file mode 100644
index 00000000000..0581acd4dfc
Binary files /dev/null and b/docs/images/GroupCompanyName.png differ
diff --git a/docs/images/GroupJobTitle.png b/docs/images/GroupJobTitle.png
new file mode 100644
index 00000000000..13d3d41b5dc
Binary files /dev/null and b/docs/images/GroupJobTitle.png differ
diff --git a/docs/images/GroupStatus.png b/docs/images/GroupStatus.png
new file mode 100644
index 00000000000..fd64ce92604
Binary files /dev/null and b/docs/images/GroupStatus.png differ
diff --git a/docs/images/ListActivityDiagram.png b/docs/images/ListActivityDiagram.png
new file mode 100644
index 00000000000..67da8b3266e
Binary files /dev/null and b/docs/images/ListActivityDiagram.png differ
diff --git a/docs/images/ListArchivedActivityDiagram.png b/docs/images/ListArchivedActivityDiagram.png
new file mode 100644
index 00000000000..bba81898259
Binary files /dev/null and b/docs/images/ListArchivedActivityDiagram.png differ
diff --git a/docs/images/ListTaskActivityDiagram.png b/docs/images/ListTaskActivityDiagram.png
new file mode 100644
index 00000000000..15f0d896afd
Binary files /dev/null and b/docs/images/ListTaskActivityDiagram.png differ
diff --git a/docs/images/ListTodoActivityDiagram.png b/docs/images/ListTodoActivityDiagram.png
new file mode 100644
index 00000000000..63535e8bcfe
Binary files /dev/null and b/docs/images/ListTodoActivityDiagram.png differ
diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png
index 9e9ba9f79e5..da3a3aede4e 100644
Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png differ
diff --git a/docs/images/MixedPanelRef.png b/docs/images/MixedPanelRef.png
new file mode 100644
index 00000000000..31583d8e73b
Binary files /dev/null and b/docs/images/MixedPanelRef.png differ
diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png
index 04070af60d8..9a834a4ea73 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/NoteOverviewDiagram.png b/docs/images/NoteOverviewDiagram.png
new file mode 100644
index 00000000000..5eb6a684c0e
Binary files /dev/null and b/docs/images/NoteOverviewDiagram.png differ
diff --git a/docs/images/PanelsRef.png b/docs/images/PanelsRef.png
new file mode 100644
index 00000000000..60168566323
Binary files /dev/null and b/docs/images/PanelsRef.png differ
diff --git a/docs/images/ParserClasses.png b/docs/images/ParserClasses.png
index e7b4c8880cd..a411bb7a2dd 100644
Binary files a/docs/images/ParserClasses.png and b/docs/images/ParserClasses.png differ
diff --git a/docs/images/RevertActivityDiagram.png b/docs/images/RevertActivityDiagram.png
new file mode 100644
index 00000000000..d084fcd10f0
Binary files /dev/null and b/docs/images/RevertActivityDiagram.png differ
diff --git a/docs/images/RevertAllSequenceDiagram.png b/docs/images/RevertAllSequenceDiagram.png
new file mode 100644
index 00000000000..3fa0bf9c9f4
Binary files /dev/null and b/docs/images/RevertAllSequenceDiagram.png differ
diff --git a/docs/images/SortSequenceDiagram.png b/docs/images/SortSequenceDiagram.png
new file mode 100644
index 00000000000..71846857e24
Binary files /dev/null and b/docs/images/SortSequenceDiagram.png differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
index 2533a5c1af0..8e3f5541345 100644
Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 5bd77847aa2..1f0fe290758 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png
index 785e04dbab4..021c4e4446b 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/docs/images/benjamin-wee.png b/docs/images/benjamin-wee.png
new file mode 100644
index 00000000000..0a12937ed17
Binary files /dev/null and b/docs/images/benjamin-wee.png differ
diff --git a/docs/images/jianminglok.png b/docs/images/jianminglok.png
new file mode 100644
index 00000000000..0292476d1ad
Binary files /dev/null and b/docs/images/jianminglok.png differ
diff --git a/docs/images/jiasheng59.png b/docs/images/jiasheng59.png
new file mode 100644
index 00000000000..ca62d99082e
Binary files /dev/null and b/docs/images/jiasheng59.png differ
diff --git a/docs/images/laihuiqi.png b/docs/images/laihuiqi.png
new file mode 100644
index 00000000000..b8e6f4fa623
Binary files /dev/null and b/docs/images/laihuiqi.png differ
diff --git a/docs/images/ui/GuiOverview.png b/docs/images/ui/GuiOverview.png
new file mode 100644
index 00000000000..8e2d10e4b04
Binary files /dev/null and b/docs/images/ui/GuiOverview.png differ
diff --git a/docs/images/ui/buttons/add-internship-button.png b/docs/images/ui/buttons/add-internship-button.png
new file mode 100644
index 00000000000..dac068103a2
Binary files /dev/null and b/docs/images/ui/buttons/add-internship-button.png differ
diff --git a/docs/images/ui/buttons/archive-internship-button.png b/docs/images/ui/buttons/archive-internship-button.png
new file mode 100644
index 00000000000..fa2f2705bc6
Binary files /dev/null and b/docs/images/ui/buttons/archive-internship-button.png differ
diff --git a/docs/images/ui/buttons/delete-internship-button.png b/docs/images/ui/buttons/delete-internship-button.png
new file mode 100644
index 00000000000..b191188066d
Binary files /dev/null and b/docs/images/ui/buttons/delete-internship-button.png differ
diff --git a/docs/images/ui/buttons/edit-internship-button.png b/docs/images/ui/buttons/edit-internship-button.png
new file mode 100644
index 00000000000..b6f615dbdcc
Binary files /dev/null and b/docs/images/ui/buttons/edit-internship-button.png differ
diff --git a/docs/images/ui/popups/add-internship-popup.png b/docs/images/ui/popups/add-internship-popup.png
new file mode 100644
index 00000000000..b283aa2c5a2
Binary files /dev/null and b/docs/images/ui/popups/add-internship-popup.png differ
diff --git a/docs/images/ui/popups/edit-internship-popup.png b/docs/images/ui/popups/edit-internship-popup.png
new file mode 100644
index 00000000000..d98273e7fd9
Binary files /dev/null and b/docs/images/ui/popups/edit-internship-popup.png differ
diff --git a/docs/images/zm-l.png b/docs/images/zm-l.png
new file mode 100644
index 00000000000..82a784e0ac9
Binary files /dev/null and b/docs/images/zm-l.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..8d5e1023820 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,17 +1,17 @@
---
layout: page
-title: AddressBook Level-3
+title: InternEase
---
-[![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)
+[![CI Status](https://github.com/AY2223S2-CS2103T-W15-4/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2223S2-CS2103T-W15-4/tp/actions)
+[![codecov](https://codecov.io/gh/AY2223S2-CS2103T-W15-4/tp/branch/master/graph/badge.svg?token=MVV9ABQAS8)](https://codecov.io/gh/AY2223S2-CS2103T-W15-4/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).
+**InternEase is a desktop application for managing your internship applications.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
-* 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.
+* If you are interested in using InternEase, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
+* If you are interested about developing InternEase, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
diff --git a/docs/team/benjamin-wee.md b/docs/team/benjamin-wee.md
new file mode 100644
index 00000000000..99f4d681beb
--- /dev/null
+++ b/docs/team/benjamin-wee.md
@@ -0,0 +1,47 @@
+---
+layout: page
+title: Benjamin Wee's Project Portfolio Page
+---
+
+### Project: InternEase
+
+InternEase is a **powerful and innovative desktop app designed to streamline the internship application process** for **Computer Science undergraduates**. With its optimized **combination of a Command Line Interface (CLI) and Graphical User Interface (GUI)**, InternEase offers users the best of both worlds - the speed and efficiency of a CLI for those who can type quickly, and the user-friendly experience of a GUI for those who prefer a visual interface. InternEase is a good choice for you who wants to concentrate on your internship preparation by helping to manage your internship applications' data.
+
+Listed below are my contributions to the project.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=benjamin-wee&breakdown=true&sort=groupTitle&sortWithin=title&since=2023-02-17&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+* **New Features**:
+ * Manage the interview date of an internship application
+ * What it does: Users are able to add an interview date to an internship application
+ * Justification: This feature allows the user, an internship applicant in this case to quickly retrieve the interview date of an application.
+ * Highlights: A Date Time validation feature had to be implemented to ensure that the date and time provided by the user is valid.
+ * Credits: Some parts of the code was reused and adapted from the [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative](https://se-education.org/).
+ * Remind the user of the internship application with the most imminent interview date
+ * What it does: Users are able to view the details of the internship application with the interview that is the nearest to the current date and time in a pop-up window every time they launch the application/execute the `remind` command.
+ * This feature allows users to quickly identify the application with an interview date that is closest to the current date and time, so that they will not miss the interview.
+ * Credits: Some parts of the code was reused and adapted from the [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative](https://se-education.org/).
+
+
+* **Project management**:
+ * Managed release `v1.2` on GitHub.
+
+* **Enhancements to existing features**:
+ * Enhanced `list` feature according to the InternEase model in [#122](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/122)
+ * Added implementation of the reminder button as part of our GUI enhancement.
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features below in [#208](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/208), [#68](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/68)
+ * `add_date`, `remind`
+ * `list`
+ * Developer Guide:
+ * Added table of contents in [#306](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/306)
+ * Added implementation details for `add_date` in [#150](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/150)
+ * Added implementation details for `remind` in [#314](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/314)
+
+* **Community**:
+ * Reported bugs and suggestions for other teams in the class : [Team CS2103T-F12-2](https://github.com/benjamin-wee/ped/issues)
+
+* **Tools**:
+ * Java 11 and JavaFX
diff --git a/docs/team/jianminglok.md b/docs/team/jianminglok.md
new file mode 100644
index 00000000000..d25b1e29c77
--- /dev/null
+++ b/docs/team/jianminglok.md
@@ -0,0 +1,60 @@
+---
+layout: page
+title: Lok Jian Ming's Project Portfolio Page
+---
+
+### Project: InternEase
+
+InternEase is a **powerful and innovative desktop app designed to streamline the internship application process** for **Computer Science undergraduates**. With its optimized **combination of a Command Line Interface (CLI) and Graphical User Interface (GUI)**, InternEase offers users the best of both worlds - the speed and efficiency of a CLI for those who can type quickly, and the user-friendly experience of a GUI for those who prefer a visual interface. InternEase is a good choice for you who wants to concentrate on your internship preparation by helping to manage your internship applications' data.
+
+Given below are my contributions to the project.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=jianminglok&breakdown=true)
+
+* **New Features**:
+ * Manage the company contact of an internship application
+ * What it does: Users are able to add a company contact, which consists of both a phone and an email to an internship application, and subsequently edit and remove it.
+ * Justification: This feature allows the user, an internship applicant in this case to quickly retrieve the contact details of an application, so that he can make an enquiry or ask for an update on his/her application status, making his/her internship application journey even easier.
+ * Highlights: The regular expression used for validating the email from the user input was updated, which was challenging in the sense that those available on the Internet were not always correct and had to be carefully modified and adapted.
+ * Credits: Some parts of the code was reused and adapted from the [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative](https://se-education.org/).
+ * Manage the documents of an internship application
+ * What it does: Users are able to add links to documents consisting of a resume and a cover letter to an internship application, and edit and remove them afterwards.
+ * Justification: This features allows users to retrieve the specific version of their resume and cover letter submitted for a particular application for reference before an interview.
+ * Highlights: A URL validation feature had to be implemented to ensure that the links to the documents provided by the user are valid.
+ * Edit the status of an internship application
+ * What it does: Users are able to update the status of their application to one of the following: `PENDING`, `RECEIVED`, `ACCEPTED`, `DECLINED`, `REJECTED`.
+ * Justification: This feature allows users to quickly identify the status of an application, so that they will not need to repeatedly check their email for the latest response, if any from the company.
+ * Highlights: Enumerations are used to ensure that the status provided is valid.
+ * Archive an internship application
+ * What is does: Users are able to archive and unarchive an internship application. They can also view a list of archived applications.
+ * Justification: This features allow users to focus on the currently ongoing internship applications, without having their list of applications getting cluttered up over time.
+ * Highlights: New predicates were created to allow ongoing and archived internship applications to be listed separately.
+* **Project management**:
+ * Setup and added Codecov label for the team project
+
+* **Enhancements to existing features**:
+ * Updated the `list` feature to only show ongoing internship applications, separating out the archived ones in [#138](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/138).
+ * Added implementation of the `ViewContentPanel` class as part of our GUI enhancement in [#165](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/165).
+ * Updated the RegEx (regular expression) for validating email addresses in [#266](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/266).
+ * Credits: Some parts of the code was reused and adapted from the [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative](https://se-education.org/).
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features below in [#45](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/45), [#217](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/217) and [#267](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/267).
+ * `add_contact`, `edit_contact`, `delete_contact`
+ * `add_docs`, `edit_docs`, `delete_docs`
+ * `archive`, `unarchive`, `list_archived`
+ * `edit_status`
+ * Developer Guide:
+ * Added use cases, implementation details and UML diagrams for the features below in [#61](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/61), [#287](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/287) and [#288](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/288).
+ * `add_contact`, `edit_contact`, `delete_contact`
+ * `add_docs`, `edit_docs`, `delete_docs`
+ * `archive`, `unarchive`, `list_archived`
+ * `edit_status`
+
+* **Community**:
+ * PRs reviewed (with non-trivial review comments): [#141](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/141), [#160](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/160)
+ * Reported bugs and suggestions for other teams in the class: [Team CS2103T-W11-3](https://github.com/jianminglok/ped/issues)
+
+* **Tools**:
+ * Java 11 and JavaFX
diff --git a/docs/team/jiasheng59.md b/docs/team/jiasheng59.md
new file mode 100644
index 00000000000..67ebc398483
--- /dev/null
+++ b/docs/team/jiasheng59.md
@@ -0,0 +1,57 @@
+---
+layout: page
+title: Lee Jia Sheng's Project Portfolio Page
+---
+
+### Project: InternEase
+
+InternEase is a powerful and innovative desktop app designed to streamline the internship application process for Computer Science undergraduates.
+With its optimized combination of a Command Line Interface (CLI) and Graphical User Interface (GUI),
+InternEase offers users the best of both worlds - the speed and efficiency
+of a CLI for those who can type quickly, and the user-friendly experience of a GUI for those who prefer a visual interface.
+If you are new to internship application, InternEase will definitely be your best buddy that gets you started smoothly.
+
+Given below are my contributions to the project.
+
+* **New Feature**: Added a summary panel to show statistics of internship applications made.
+ * What it does: allows the user to have an overview to current status of internship applications.
+ * Justification: This feature improves the product in terms of visualising data into a more intuitive form and helps user to better manage those applications which have yet to received reply.
+ * Highlights: This enhancement not only support summarising existing status of internship applications implemented but also will support any further internship status to be implemented in future automatically. It's complete in the sense that it's complete and not hard-coded so by introducing new `status`, it won't require any changes in this portion.
+ * Disclaimer: The GUI design of the summary panel references the design of `ListView` panel of AB3 which is the upstream repo InternEase forked from.
+
+* **New Feature**: Added a sort command that allows the user to sort all applications by company name, job title, application status and interview dates.
+ * What it does: allows the user to have a sorted view of the list of internship applications by above-mentioned attributes.
+ * Justification: This feature makes the product more user-friendly as the user is able to better manage large volume of applications made and view the relatively more urgent internship applications using sort by interview date command.
+ * Highlights: This enhancement is challenging to implement as it requires changing the underlying representation of the internship application list without breaking the abstraction barrier, so that other commands relying on the initial representation don't break after the change.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=jiasheng59&breakdown=true&sort=groupTitle%20dsc&sortWithin=title&since=2023-02-17&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+* **Project management**:
+ * Set up the GitHub team org and repo
+ * Lead the discussion in weekly project meeting
+ * Encourage teammates to brainstorm for Unique Selling Point of InternEase at the end of v1.2 iteration
+ * Managed releases `v1.3` - `v1.4` (2 releases) on GitHub
+
+* **Enhancements to existing features**: Enhanced the find command that allows the user to find internship application by the company name, job title, application status and interview date(s).
+ * What it does: allows the user to find an internship application by matching keyword for the company name and job title, by a specified application status, and by specifying a range of dates where the interview date falls within.
+ * Justification: This feature makes the product more user-friendly as the user is able to search through the list with huge number of applications efficiently and makes subsequent changes.
+ * Highlights: This enhancement is challenging to implement as to make the command format as `defensive` as it could be, the checking in parser is somewhat exponential.
+
+* **Enhancements to existing features: Others**:
+ * Updated the help command link to current UG
+ * Wrote additional tests for new and existing features to increase coverage from 36.91% to 39.83% (Pull requests [\#290](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/290))
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `list`, `help`, `sort` and `find`: [\#200](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/200), [\#210](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/210), [\#212](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/212)
+ * Did cosmetic tweaks to existing documentation of features: [\#291](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/291)
+ * Developer Guide:
+ * Added implementation details of the `list`, `sort`, and `find` feature and corresponding use cases
+ * Drew related UML diagrams for better illustration
+
+* **Community**:
+ * PRs reviewed (with non-trivial review comments): [\#106](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/106), [\#129](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/129),
+[\#130](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/130), [\#131](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/131), [\#132](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/132),
+[\#133](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/133), [\#147](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/147), [\#155](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/155), [\#262](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/262)
+ * Contributed to forum discussions (examples: [1](https://github.com/nus-cs2103-AY2223S2/forum/issues/239#issuecomment-1454813105), [2](https://github.com/nus-cs2103-AY2223S2/forum/issues/294#issuecomment-1489103419), [3](https://github.com/nus-cs2103-AY2223S2/forum/issues/294), [4](https://github.com/nus-cs2103-AY2223S2/forum/issues/247#issuecomment-1460008541))
+ * Reported bugs and suggestions for other teams in the class (examples: [1](https://github.com/AY2223S2-CS2103T-W13-3/tp/issues/161#event-8953814014))
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/laihuiqi.md b/docs/team/laihuiqi.md
new file mode 100644
index 00000000000..8d80495d82a
--- /dev/null
+++ b/docs/team/laihuiqi.md
@@ -0,0 +1,53 @@
+---
+layout: page
+title: Lai Hui Qi's Project Portfolio Page
+---
+### Project: InternEase
+
+InternEase is a **powerful and innovative desktop app designed to streamline the internship application process** for **Computer Science undergraduates**. It is a good choice for you to concentrate on your internship preparation as it helps to manage your internship applications' data.
+
+Given below are my contributions to the project.
+**Code contributed**: [RepoSense link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=laihuiqi&breakdown=true&sort=groupTitle&sortWithin=title&since=2023-02-17&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+**Credits**: Some code reused and adapted from [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative](https://se-education.org/).
+
+**New Feature**: Adds the ability to plan an internship application by introducing a `task package` with subpackages `todo` and `note`.
+* Allows user to plan future internship applications and record long-lasting reminders to enhance future internship applications and interviews.
+* `task` package : `find_task` and `list_task`.
+* `todo` package : `add_todo`, `clear_todo`, `delete_todo`, `edit_deadline`, `edit_content` and `list_todo`.
+* `note` package : `add_note`, `clear_note`, `delete_note` and `list_note`.
+* Justification: Provides functional spaces for planning internships and preparing interviews.
+* Highlights: An independent structure of logic, model, storage and ui is implemented for this side features package to avoid ambiguity.
+* **Credits**: Some code reused and adapted from [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative](https://se-education.org/).
+
+**New Feature**: Clears the internship applications with specified attributes and keywords
+* Allows user to delete internship applications at once by `company name`, `job title` or `status` with keywords specified (`clear_by`).
+* Justification: Enable more efficient cleaned-up for unwanted internship applications.
+* Highlights: The implementation of different class constructors and their respective parse functions is slightly challenging.
+* **Credits**: Some code reused and adapted from [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative](https://se-education.org/).
+
+**New Feature**: Reverts the recent deletion of internship application
+* Allows user to restore the most recent internship application from the CacheList.
+* Justification: Resolves the situation when the user accidentally deletes an internship application with many important particulars.
+* Highlights: CacheList is implemented to be the data structure to hold the deleted or cleared internship applications temporarily.
+* **Credits**: Some code reused and adapted from [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative](https://se-education.org/).
+
+**Project management (Team-based tasks)**:
+* Added labels and modified label descriptions for issues, updated README.md and index.md. [\#59](https://github.com/AY2223S2-CS2103T-W15-4/tp/issues/59)
+* Modified documentation for Quick Start and added table of contents for User Guide. [\#47](https://github.com/AY2223S2-CS2103T-W15-4/tp/issues/47), [\#161](https://github.com/AY2223S2-CS2103T-W15-4/tp/issues/161)
+
+**Enhancements implemented**:
+* Enhanced `clear`, `delete` and `exit` features according to the InternEase model.
+* Enhanced GUI interface for `MainWindow`, `Result Dialog` and `task package` related GUI parts. [\#128](https://github.com/AY2223S2-CS2103T-W15-4/tp/issues/128), [\#162](https://github.com/AY2223S2-CS2103T-W15-4/tp/issues/162)
+* Enhanced test cases for assigned features, increased related class test coverage to at least 80%.[\#272](https://github.com/AY2223S2-CS2103T-W15-4/tp/issues/272)
+* **Credits**: Some code reused and adapted from [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative](https://se-education.org/).
+
+**Documentation**:
+* User Guide:
+ * Updated documentation for main features and side features stated above [\#47](https://github.com/AY2223S2-CS2103T-W15-4/tp/issues/47), [\#161](https://github.com/AY2223S2-CS2103T-W15-4/tp/issues/161)
+* Developer Guide:
+ * Added use cases, implementation details and UML diagrams for all features stated above and `Ui component`. [\#52](https://github.com/AY2223S2-CS2103T-W15-4/tp/issues/52), [\#274](https://github.com/AY2223S2-CS2103T-W15-4/tp/issues/274)
+* **Credits**: Some code reused and adapted from [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative](https://se-education.org/).
+
+**Community**:
+* PRs reviewed (with non-trivial review comments): [\#145](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/145), [\#157](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/157), [\#173](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/173), [\#266](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/266)
+* Reported bugs and suggestions for other teams in PE-D: [PE-D Group W16-1](https://github.com/laihuiqi/ped/issues)
diff --git a/docs/team/zm-l.md b/docs/team/zm-l.md
new file mode 100644
index 00000000000..bf33e7ba0b9
--- /dev/null
+++ b/docs/team/zm-l.md
@@ -0,0 +1,42 @@
+---
+layout: page
+title: Lau Zhan Ming's Project Portfolio Page
+---
+
+### Project: InternEase
+
+InternEase is a **powerful and innovative desktop app designed to streamline the internship application process** for **Computer Science undergraduates**. With its optimized **combination of a Command Line Interface (CLI) and Graphical User Interface (GUI)**, InternEase offers users the best of both worlds - the speed and efficiency of a CLI for those who can type quickly, and the user-friendly experience of a GUI for those who prefer a visual interface. InternEase is a good choice for you who wants to concentrate on your internship preparation by helping to manage your internship applications' data.
+
+Given below are my contributions to the project.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=zm-l&breakdown=true)
+
+* **New Feature**:
+ * Manage an internship application
+ * What it does: Users are able to add and edit internship application
+ * Justification: This feature allows the user, an internship applicant in this case to add and edit an internship application they have.
+ * Highlights: Regular expressions are used to ensure user are typing in correct informations. Some fields are left as optional to give user more freedom to insert relevant details.
+ * Credits: Some parts of the code was reused and adapted from the [AB3 project](https://github.com/nus-cs2103-AY2223S2/tp) created by the [SE-EDU initiative]
+
+* **Project management**:
+ * Managed release `v1.1` on GitHub.
+
+* **Enhancements to existing features**:
+ * Improved UI/UX by designing and implementing a form for user to type in details when using the `add` and `edit` command.
+ * Implemented buttons for `add`, `edit`, `delete`, `archive` and `unarchive` command.
+ * Wrote additional tests for existing features to increase coverage from 49% to 69% (Pull requests [#326](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/326), [#330](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/330), [#331](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/331), [#333](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/333))
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `add` and `edit` command in [#211](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/211).
+ * Developer Guide:
+ * Added use cases for `add` command in [#143](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/143)
+ * Added use cases for `edit` command in [#298](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/298)
+
+* **Community**:
+ * PRs reviewed (with non-trivial review comments): [262](https://github.com/AY2223S2-CS2103T-W15-4/tp/pull/262)
+ * Contributed to forum discussions (examples: [1](https://github.com/nus-cs2103-AY2223S2/forum/issues/360))
+ * Reported bugs and suggestions for other teams in the class: [CS2103-W17-4](https://github.com/zm-l/ped/issues)
+
+* **Tools**:
+ * Java 11 and Java FX
diff --git a/docs/tutorials/AddRemark.md b/docs/tutorials/AddRemark.md
index 880c701042f..715cc336e0d 100644
--- a/docs/tutorials/AddRemark.md
+++ b/docs/tutorials/AddRemark.md
@@ -229,7 +229,7 @@ Now that we have all the information that we need, let’s lay the groundwork fo
### Add a new `Remark` class
-Create a new `Remark` in `seedu.address.model.person`. Since a `Remark` is a field that is similar to `Address`, we can reuse a significant bit of code.
+Create a new `Remark` in `seedu.address.model.application`. Since a `Remark` is a field that is similar to `Address`, we can reuse a significant bit of code.
A copy-paste and search-replace later, you should have something like [this](https://github.com/se-edu/addressbook-level3/commit/4516e099699baa9e2d51801bd26f016d812dedcc#diff-41bb13c581e280c686198251ad6cc337cd5e27032772f06ed9bf7f1440995ece). Note how `Remark` has no constrains and thus does not require input
validation.
@@ -242,7 +242,7 @@ Let’s change `RemarkCommand` and `RemarkCommandParser` to use the new `Remark`
Without getting too deep into `fxml`, let’s go on a 5 minute adventure to get some placeholder text to show up for each person.
-Simply add the following to [`seedu.address.ui.PersonCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-639834f1e05afe2276a86372adf0fe5f69314642c2d93cfa543d614ce5a76688).
+Simply add the following to [`seedu.address.ui.ApplicationCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-639834f1e05afe2276a86372adf0fe5f69314642c2d93cfa543d614ce5a76688).
**`PersonCard.java`:**
diff --git a/docs/tutorials/RemovingFields.md b/docs/tutorials/RemovingFields.md
index f29169bc924..d89e990a1d6 100644
--- a/docs/tutorials/RemovingFields.md
+++ b/docs/tutorials/RemovingFields.md
@@ -28,7 +28,7 @@ IntelliJ IDEA provides a refactoring tool that can identify *most* parts of a re
### Assisted refactoring
-The `address` field in `Person` is actually an instance of the `seedu.address.model.person.Address` class. Since removing the `Address` class will break the application, we start by identifying `Address`'s usages. This allows us to see code that depends on `Address` to function properly and edit them on a case-by-case basis. Right-click the `Address` class and select `Refactor` \> `Safe Delete` through the menu.
+The `address` field in `Person` is actually an instance of the `seedu.address.model.application.Address` class. Since removing the `Address` class will break the application, we start by identifying `Address`'s usages. This allows us to see code that depends on `Address` to function properly and edit them on a case-by-case basis. Right-click the `Address` class and select `Refactor` \> `Safe Delete` through the menu.
* :bulb: To make things simpler, you can unselect the options `Search in comments and strings` and `Search for text occurrences`
![Usages detected](../images/remove/UnsafeDelete.png)
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java
index 4133aaa0151..a9843f7607b 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/address/MainApp.java
@@ -18,9 +18,14 @@
import seedu.address.model.AddressBook;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
+import seedu.address.model.NoteList;
import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyNote;
+import seedu.address.model.ReadOnlyTodoList;
import seedu.address.model.ReadOnlyUserPrefs;
+import seedu.address.model.TodoList;
import seedu.address.model.UserPrefs;
+import seedu.address.model.statstics.StatsManager;
import seedu.address.model.util.SampleDataUtil;
import seedu.address.storage.AddressBookStorage;
import seedu.address.storage.JsonAddressBookStorage;
@@ -28,6 +33,10 @@
import seedu.address.storage.Storage;
import seedu.address.storage.StorageManager;
import seedu.address.storage.UserPrefsStorage;
+import seedu.address.storage.task.note.JsonNoteListStorage;
+import seedu.address.storage.task.note.NoteStorage;
+import seedu.address.storage.task.todo.JsonTodoListStorage;
+import seedu.address.storage.task.todo.TodoListStorage;
import seedu.address.ui.Ui;
import seedu.address.ui.UiManager;
@@ -36,7 +45,7 @@
*/
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, 0, true);
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
@@ -44,6 +53,7 @@ public class MainApp extends Application {
protected Logic logic;
protected Storage storage;
protected Model model;
+ protected StatsManager statsManager;
protected Config config;
@Override
@@ -57,13 +67,19 @@ 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);
+ TodoListStorage todoListStorage = new JsonTodoListStorage(userPrefs.getTodoListFilePath());
+ NoteStorage noteStorage = new JsonNoteListStorage(userPrefs.getNoteListFilePath());
+
+ storage = new StorageManager(addressBookStorage, userPrefsStorage, todoListStorage, noteStorage);
+
initLogging(config);
model = initModelManager(storage, userPrefs);
- logic = new LogicManager(model, storage);
+ statsManager = new StatsManager(model);
+
+ logic = new LogicManager(model, storage, statsManager);
ui = new UiManager(logic);
}
@@ -74,6 +90,14 @@ public void init() throws Exception {
* or an empty address book will be used instead if errors occur when reading {@code storage}'s address book.
*/
private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
+ ReadOnlyAddressBook initialAddressBook = initModelAddressBook(storage);
+ ReadOnlyTodoList initialTodoList = initModelTodoList(storage);
+ ReadOnlyNote initialNoteList = initModelNoteList(storage);
+
+ return new ModelManager(initialAddressBook, userPrefs, initialTodoList, initialNoteList);
+ }
+
+ private ReadOnlyAddressBook initModelAddressBook(Storage storage) {
Optional addressBookOptional;
ReadOnlyAddressBook initialData;
try {
@@ -90,7 +114,47 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
initialData = new AddressBook();
}
- return new ModelManager(initialData, userPrefs);
+ return initialData;
+ }
+
+ private ReadOnlyTodoList initModelTodoList(Storage storage) {
+ Optional todoListOptional;
+ ReadOnlyTodoList initialData;
+ try {
+ todoListOptional = storage.readTodoList();
+ if (!todoListOptional.isPresent()) {
+ logger.info("Data file not found. Will be starting with a sample todolist");
+ }
+ initialData = todoListOptional.orElseGet(SampleDataUtil::getSampleTodoList);
+ } catch (DataConversionException e) {
+ logger.warning("Data file not in the correct format. Will be starting with an empty todolist");
+ initialData = new TodoList();
+ } catch (IOException e) {
+ logger.warning("Problem while reading from the file. Will be starting with an empty todolist");
+ initialData = new TodoList();
+ }
+
+ return initialData;
+ }
+
+ private ReadOnlyNote initModelNoteList(Storage storage) {
+ Optional noteListOptional;
+ ReadOnlyNote initialData;
+ try {
+ noteListOptional = storage.readNoteList();
+ if (!noteListOptional.isPresent()) {
+ logger.info("Data file not found. Will be starting with a sample note list");
+ }
+ initialData = noteListOptional.orElseGet(SampleDataUtil::getSampleNoteList);
+ } catch (DataConversionException e) {
+ logger.warning("Data file not in the correct format. Will be starting with an empty note list");
+ initialData = new NoteList();
+ } catch (IOException e) {
+ logger.warning("Problem while reading from the file. Will be starting with an empty note list");
+ initialData = new NoteList();
+ }
+
+ return initialData;
}
private void initLogging(Config config) {
diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/address/commons/core/GuiSettings.java
index ba33653be67..6bf49afc827 100644
--- a/src/main/java/seedu/address/commons/core/GuiSettings.java
+++ b/src/main/java/seedu/address/commons/core/GuiSettings.java
@@ -10,8 +10,8 @@
*/
public class GuiSettings implements Serializable {
- private static final double DEFAULT_HEIGHT = 600;
- private static final double DEFAULT_WIDTH = 740;
+ private static final double DEFAULT_HEIGHT = 700;
+ private static final double DEFAULT_WIDTH = 1285;
private final double windowWidth;
private final double windowHeight;
diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java
index 1deb3a1e469..581b3dbd499 100644
--- a/src/main/java/seedu/address/commons/core/Messages.java
+++ b/src/main/java/seedu/address/commons/core/Messages.java
@@ -7,7 +7,13 @@ 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!";
-
+ public static final String MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX =
+ "The application index provided is invalid";
+ public static final String MESSAGE_INVALID_TODO_DISPLAYED_INDEX =
+ "The todo index provided is invalid";
+ public static final String MESSAGE_INVALID_NOTE_DISPLAYED_INDEX =
+ "The note index provided is invalid";
+ public static final String MESSAGE_APPLICATION_LISTED_OVERVIEW = "%1$d applications listed!";
+ public static final String MESSAGE_INVALID_DISPLAYED_INDEX = "This provided index is invalid!";
+ public static final String MESSAGE_RESULT_LISTED_OVERVIEW = "%1$d tasks listed!";
}
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java
index 92cd8fa605a..7861fa2d271 100644
--- a/src/main/java/seedu/address/logic/Logic.java
+++ b/src/main/java/seedu/address/logic/Logic.java
@@ -8,7 +8,10 @@
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;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.statstics.StatsManager;
+import seedu.address.model.task.InternshipTodo;
+import seedu.address.model.task.Note;
/**
* API of the Logic component
@@ -30,14 +33,41 @@ public interface Logic {
*/
ReadOnlyAddressBook getAddressBook();
- /** Returns an unmodifiable view of the filtered list of persons */
- ObservableList getFilteredPersonList();
+ /**
+ * Returns a StatsManager.
+ */
+ StatsManager getStatsManager();
+
+ /** Returns an unmodifiable view of the filtered list of internship applications. */
+ ObservableList getFilteredInternshipList();
+
+ /** Returns an unmodifiable view of the sorted filtered list of internship applications */
+ ObservableList getSortedFilteredInternshipList();
+
+ /** Returns an unmodifiable view of the filtered list of todos. */
+ ObservableList getFilteredTodoList();
+
+ /** Returns an unmodifiable view of the filtered list of notes. */
+ ObservableList getFilteredNoteList();
+
+ /** Returns the InternshipApplication with the most imminent interview*/
+ InternshipApplication getReminderApplication();
/**
* Returns the user prefs' address book file path.
*/
Path getAddressBookFilePath();
+ /**
+ * Returns the user prefs' todo list file path.
+ */
+ Path getTodoListFilePath();
+
+ /**
+ * Returns the user prefs' note list file path.
+ */
+ Path getNoteListFilePath();
+
/**
* Returns the user prefs' GUI settings.
*/
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java
index 9d9c6d15bdc..2f75ffbe576 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/address/logic/LogicManager.java
@@ -10,11 +10,15 @@
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.InternEaseParser;
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.model.application.InternshipApplication;
+import seedu.address.model.statstics.StatsManager;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.InternshipTodo;
+import seedu.address.model.task.Note;
import seedu.address.storage.Storage;
/**
@@ -26,15 +30,17 @@ public class LogicManager implements Logic {
private final Model model;
private final Storage storage;
- private final AddressBookParser addressBookParser;
+ private final StatsManager statsManager;
+ private final InternEaseParser internEaseParser;
/**
* Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}.
*/
- public LogicManager(Model model, Storage storage) {
+ public LogicManager(Model model, Storage storage, StatsManager statsManager) {
this.model = model;
this.storage = storage;
- addressBookParser = new AddressBookParser();
+ this.statsManager = statsManager;
+ internEaseParser = new InternEaseParser();
}
@Override
@@ -42,11 +48,19 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
logger.info("----------------[USER COMMAND][" + commandText + "]");
CommandResult commandResult;
- Command command = addressBookParser.parseCommand(commandText);
+ Command command = internEaseParser.parseCommand(commandText);
commandResult = command.execute(model);
+ statsManager.updateAllStatsInformation();
try {
- storage.saveAddressBook(model.getAddressBook());
+ if (commandResult.getType() == TaskType.NONE) {
+ storage.saveAddressBook(model.getAddressBook());
+ } else if (commandResult.getType() == TaskType.TODO) {
+ storage.saveTodoList(model.getTodoList());
+ } else if (commandResult.getType() == TaskType.NOTE) {
+ storage.saveNoteList(model.getNoteList());
+ }
+
} catch (IOException ioe) {
throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe);
}
@@ -60,15 +74,50 @@ public ReadOnlyAddressBook getAddressBook() {
}
@Override
- public ObservableList getFilteredPersonList() {
- return model.getFilteredPersonList();
+ public StatsManager getStatsManager() {
+ return statsManager;
+ }
+
+ @Override
+ public ObservableList getFilteredInternshipList() {
+ return model.getSortedFilteredInternshipList();
}
+ @Override
+ public ObservableList getSortedFilteredInternshipList() {
+ return model.getSortedFilteredInternshipList();
+ }
+
+ @Override
+ public ObservableList getFilteredTodoList() {
+ return model.getFilteredTodoList();
+ }
+
+ @Override
+ public ObservableList getFilteredNoteList() {
+ return model.getFilteredNoteList();
+ }
+
+ @Override
+ public InternshipApplication getReminderApplication() {
+ model.updateReminder();
+ return model.getReminder();
+ }
@Override
public Path getAddressBookFilePath() {
return model.getAddressBookFilePath();
}
+ @Override
+ public Path getTodoListFilePath() {
+ return model.getTodoListFilePath();
+ }
+
+ @Override
+ public Path getNoteListFilePath() {
+ return model.getNoteListFilePath();
+ }
+
@Override
public GuiSettings getGuiSettings() {
return model.getGuiSettings();
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
index 71656d7c5c8..99b52b1c349 100644
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ b/src/main/java/seedu/address/logic/commands/AddCommand.java
@@ -1,60 +1,70 @@
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.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB_TITLE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LOCATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NOTE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_QUALIFICATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_RATING;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REFLECTION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REVIEW;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
-import seedu.address.model.person.Person;
+import seedu.address.model.application.InternshipApplication;
/**
- * Adds a person to the address book.
+ * Adds an application to the internship tracker.
*/
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"
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds an internship application to the tracker.\n"
+ + "Compulsory Parameters: "
+ + PREFIX_COMPANY_NAME + "COMPANY_NAME "
+ + PREFIX_JOB_TITLE + "JOB_TITLE\n"
+ + "Optional Parameters: "
+ + PREFIX_REVIEW + "REVIEW "
+ + PREFIX_LOCATION + "LOCATION "
+ + PREFIX_PROGRAMMING_LANGUAGE + "PROGRAMMING_LANGUAGE "
+ + PREFIX_QUALIFICATION + "QUALIFICATION "
+ + PREFIX_SALARY + "SALARY "
+ + PREFIX_RATING + "RATING "
+ + PREFIX_NOTE + "NOTE "
+ + PREFIX_REFLECTION + "REFLECTION\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";
+ + PREFIX_COMPANY_NAME + "LinkedIn "
+ + PREFIX_JOB_TITLE + "Software Engineer "
+ + PREFIX_REVIEW + "high learning curve, fast paced environment "
+ + PREFIX_LOCATION + "Clementi";
- 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";
+ public static final String MESSAGE_SUCCESS = "New internship application added: %1$s";
+ public static final String MESSAGE_DUPLICATE_INTERNSHIP = "This internship application "
+ + "already exists in the address book";
- private final Person toAdd;
+ private final InternshipApplication toAdd;
/**
- * Creates an AddCommand to add the specified {@code Person}
+ * Creates an AddCommand to add the specified {@code InternshipApplication}
*/
- public AddCommand(Person person) {
- requireNonNull(person);
- toAdd = person;
+ public AddCommand(InternshipApplication application) {
+ requireNonNull(application);
+ toAdd = application;
}
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- if (model.hasPerson(toAdd)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ if (model.hasApplication(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_INTERNSHIP);
}
- model.addPerson(toAdd);
+ model.addApplication(toAdd);
return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
}
diff --git a/src/main/java/seedu/address/logic/commands/AddInterviewDateCommand.java b/src/main/java/seedu/address/logic/commands/AddInterviewDateCommand.java
new file mode 100644
index 00000000000..319914058c7
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddInterviewDateCommand.java
@@ -0,0 +1,109 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+
+import java.util.List;
+import java.util.Set;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.contact.Contact;
+import seedu.address.model.documents.Documents;
+
+/**
+ * Adds an interview date to an application identified using it's displayed index from the list of internship
+ * applications.
+ */
+public class AddInterviewDateCommand extends Command {
+
+ public static final String COMMAND_WORD = "add_date";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Adds interview date to the specified application from the list of internships applied.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "[" + PREFIX_DATE + "DATE] (DATE must be in 'yyyy-MM-dd hh:mm a' format, where a can be AM or PM)"
+ + "\nExample: " + COMMAND_WORD + " 1 "
+ + PREFIX_DATE + "2023-06-07 12:00 PM";
+
+
+ public static final String MESSAGE_ADD_INTERVIEW_DATE_SUCCESS = "Interview date added to application: %1$s";
+
+ private final Index targetIndex;
+ private final InterviewDate toAdd;
+
+ /**
+ * @param targetIndex of the internship application to add interview date
+ * @param interviewDate InterviewDate to add
+ */
+ public AddInterviewDateCommand(Index targetIndex, InterviewDate interviewDate) {
+ requireNonNull(targetIndex);
+ this.targetIndex = targetIndex;
+ toAdd = interviewDate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ InternshipApplication internshipToAddInterviewDate = lastShownList.get(targetIndex.getZeroBased());
+ InternshipApplication internshipWithInterviewDate = createInternshipWithInterviewDate(
+ internshipToAddInterviewDate, toAdd);
+
+ model.setApplication(internshipToAddInterviewDate, internshipWithInterviewDate);
+ return new CommandResult(String.format(MESSAGE_ADD_INTERVIEW_DATE_SUCCESS, internshipToAddInterviewDate
+ + "\n" + toAdd));
+ }
+
+ private static InternshipApplication createInternshipWithInterviewDate(
+ InternshipApplication internshipToAddInterviewDate, InterviewDate interviewDate) {
+ assert internshipToAddInterviewDate != null;
+
+ CompanyName companyName = internshipToAddInterviewDate.getCompanyName();
+ JobTitle jobTitle = internshipToAddInterviewDate.getJobTitle();
+ Set reviews = internshipToAddInterviewDate.getReviews();
+ Set programmingLanguages = internshipToAddInterviewDate.getProgrammingLanguages();
+ Set qualifications = internshipToAddInterviewDate.getQualifications();
+ Location location = internshipToAddInterviewDate.getLocation();
+ Salary salary = internshipToAddInterviewDate.getSalary();
+ Set notes = internshipToAddInterviewDate.getNotes();
+ Rating rating = internshipToAddInterviewDate.getRating();
+ Set reflections = internshipToAddInterviewDate.getReflections();
+ Contact contact = internshipToAddInterviewDate.getContact();
+ boolean isArchived = internshipToAddInterviewDate.isArchived();
+ InternshipStatus status = internshipToAddInterviewDate.getStatus();
+ Documents documents = internshipToAddInterviewDate.getDocuments();
+
+ return new InternshipApplication(companyName, jobTitle, reviews, programmingLanguages, qualifications, location,
+ salary, notes, rating, reflections, contact, status, isArchived, interviewDate, documents);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddInterviewDateCommand // instanceof handles nulls
+ && targetIndex.equals(((AddInterviewDateCommand) other).targetIndex)
+ && toAdd.equals(((AddInterviewDateCommand) other).toAdd)); // state check
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/ArchiveCommand.java b/src/main/java/seedu/address/logic/commands/ArchiveCommand.java
new file mode 100644
index 00000000000..f6fd07f096c
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ArchiveCommand.java
@@ -0,0 +1,113 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ARCHIVED_APPLICATIONS;
+
+import java.util.List;
+import java.util.Set;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.contact.Contact;
+import seedu.address.model.documents.Documents;
+
+/**
+ * Archives an internship application identified using it's displayed index from the list of internship applications.
+ */
+public class ArchiveCommand extends Command {
+
+ public static final String COMMAND_WORD = "archive";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Archives the specified application from the list of internships applied.\n"
+ + "Archives the application of internship at the specified INDEX.\n"
+ + "The index refers to the index number shown in the displayed internship list.\n"
+ + "Parameters: INDEX (must be a positive integer 1, 2, 3, ...)\n"
+ + "Example: " + COMMAND_WORD + " 2";
+
+ public static final String MESSAGE_ARCHIVE_APPLICATION_SUCCESS = "Archived Application: %1$s";
+ public static final String MESSAGE_APPLICATION_ALREADY_ARCHIVED = "Application is already archived!";
+
+ private final Index targetIndex;
+
+ /**
+ * Creates an ArchiveCommand to archive the specified {@code targetIndex} internship
+ *
+ * @param targetIndex of the internship application to archive
+ */
+ public ArchiveCommand(Index targetIndex) {
+ requireNonNull(targetIndex);
+
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ InternshipApplication internshipToArchive = lastShownList.get(targetIndex.getZeroBased());
+
+ if (internshipToArchive.isArchived()) {
+ throw new CommandException(MESSAGE_APPLICATION_ALREADY_ARCHIVED);
+ }
+
+ InternshipApplication archivedApplication = createdArchivedApplication(internshipToArchive);
+
+ model.setApplication(internshipToArchive, archivedApplication);
+ model.updateFilteredInternshipList(PREDICATE_SHOW_ARCHIVED_APPLICATIONS);
+ return new CommandResult(String.format(MESSAGE_ARCHIVE_APPLICATION_SUCCESS, archivedApplication));
+ }
+
+ /**
+ * Creates and returns an archived {@code InternshipApplication}
+ */
+ private static InternshipApplication createdArchivedApplication(InternshipApplication internshipApplication) {
+ assert internshipApplication != null;
+
+ CompanyName companyName = internshipApplication.getCompanyName();
+ JobTitle jobTitle = internshipApplication.getJobTitle();
+ Set reviews = internshipApplication.getReviews();
+ Set programmingLanguages = internshipApplication.getProgrammingLanguages();
+ Set qualifications = internshipApplication.getQualifications();
+ Location location = internshipApplication.getLocation();
+ Salary salary = internshipApplication.getSalary();
+ Set notes = internshipApplication.getNotes();
+ Rating rating = internshipApplication.getRating();
+ Set reflections = internshipApplication.getReflections();
+ Contact contact = internshipApplication.getContact();
+ InternshipStatus status = internshipApplication.getStatus();
+ InterviewDate interviewDate = internshipApplication.getInterviewDate();
+ Documents documents = internshipApplication.getDocuments();
+
+ return new InternshipApplication(companyName, jobTitle, reviews, programmingLanguages, qualifications, location,
+ salary, notes, rating, reflections, contact, status, true, interviewDate,
+ documents);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ArchiveCommand // instanceof handles nulls
+ && targetIndex.equals(((ArchiveCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ClearByCommand.java b/src/main/java/seedu/address/logic/commands/ClearByCommand.java
new file mode 100644
index 00000000000..e1b8f6920cc
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ClearByCommand.java
@@ -0,0 +1,178 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB_TITLE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_STATUS;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.JobTitle;
+
+/**
+ * Clears the internship application entries by parameter specified.
+ */
+public class ClearByCommand extends Command {
+ /**
+ * An enum class to specify the clear_by types.
+ */
+ enum ParamType {
+ JOBTITLE("Job title"), COMPANYNAME("Company name"), STATUS("Status");
+
+ private String name;
+
+ /**
+ * Creates a string representation {@code name} for the respective ParamType.
+ */
+ ParamType(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Getter for the string representation of the respective ParamType enum object.
+ */
+ public String getName() {
+ return name;
+ }
+ }
+
+ public static final String COMMAND_WORD = "clear_by";
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Clear all relevant entries from the internship tracker with specific keyword.\n"
+ + "Clears all application with the specified keyword - COMPANY_NAME, JOB_TITLE or STATUS.\n"
+ + "Three types of clear_by features are provided, but can only execute independently.\n"
+ + "Examples: \n"
+ + COMMAND_WORD + " " + PREFIX_COMPANY_NAME + "Meta Clears all application with COMPANY_NAME as Meta.\n"
+ + COMMAND_WORD + " " + PREFIX_JOB_TITLE + "Software engineer Clears all application with JOB_TITLE as "
+ + "Software Engineer.\n"
+ + COMMAND_WORD + " " + PREFIX_STATUS
+ + "REJECTED Clears all rejected application (with STATUS as REJECTED).";
+
+ public static final String MESSAGE_INVALID_PARAMETER = "Invalid param!";
+ public static final String MESSAGE_NO_PARAMETER = "Please provide clear_by parameter!";
+ public static final String MESSAGE_CLEAR_SUCCESS = "All internship application with %s : %s has been cleared!";
+ public static final String MESSAGE_NULL = "There is nothing to clear!";
+ public static final String MESSAGE_FAILED = "Clear_by command cannot be executed!";
+ public static final String MESSAGE_EMPTY_FILTERED_LIST = "There is no %s with keyword \"%s\"!";
+
+ private CompanyName companyName = null;
+ private JobTitle jobTitle = null;
+ private InternshipStatus status = null;
+ private String param;
+
+ private ParamType paramType;
+
+ /**
+ * Creates a ClearByCommand to delete all the relevant applications that have company names match with
+ * {@code companyName}.
+ */
+ public ClearByCommand(CompanyName companyName) {
+ this.companyName = companyName;
+ param = companyName.fullName;
+ paramType = ParamType.COMPANYNAME;
+ }
+
+ /**
+ * Creates a ClearByCommand to delete all the relevant applications that have jobTitles match with
+ * {@code jobTitle}.
+ */
+ public ClearByCommand(JobTitle jobTitle) {
+ this.jobTitle = jobTitle;
+ param = jobTitle.fullName;
+ paramType = ParamType.JOBTITLE;
+ }
+
+ /**
+ * Creates a ClearByCommand to delete all the relevant applications that have statuses match with
+ * {@code status}.
+ */
+ public ClearByCommand(InternshipStatus status) {
+ this.status = status;
+ param = status.toString();
+ paramType = ParamType.STATUS;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (lastShownList.size() == 0) {
+ return new CommandResult(MESSAGE_NULL);
+ }
+
+ try {
+ ParamType.valueOf(String.valueOf(paramType));
+ List filteredList = getFilteredList(lastShownList);
+
+ if (filteredList.size() == 0) {
+ return new CommandResult(String.format(MESSAGE_EMPTY_FILTERED_LIST, paramType.getName(), param));
+ }
+
+ for (InternshipApplication application : filteredList) {
+ model.addInternshipToCache(application);
+ model.deleteInternship(application);
+ }
+
+ return new CommandResult(String.format(MESSAGE_CLEAR_SUCCESS, paramType.getName(), param));
+
+ } catch (IllegalArgumentException e) {
+ return new CommandResult(MESSAGE_FAILED);
+ }
+
+ }
+
+ private List getFilteredList(List lastShownList) {
+ List filteredList;
+ switch (paramType) {
+ case COMPANYNAME:
+ filteredList = lastShownList
+ .stream()
+ .filter(a -> (a.getCompanyName()).equals(companyName))
+ .collect(Collectors.toList());
+ break;
+ case JOBTITLE:
+ filteredList = lastShownList
+ .stream()
+ .filter(a -> (a.getJobTitle().equals(jobTitle)))
+ .collect(Collectors.toList());
+ break;
+ case STATUS:
+ filteredList = lastShownList
+ .stream()
+ .filter(a -> (a.getStatus().equals(status)))
+ .collect(Collectors.toList());
+ break;
+ default:
+ filteredList = new ArrayList<>();
+ }
+ return filteredList;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ } else if (!(other instanceof ClearByCommand)) {
+ return false;
+ }
+
+ switch (paramType) {
+ case COMPANYNAME:
+ return companyName.equals(((ClearByCommand) other).companyName);
+ case JOBTITLE:
+ return jobTitle.equals(((ClearByCommand) other).jobTitle);
+ case STATUS:
+ return status.equals(((ClearByCommand) other).status);
+ default:
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java
index 9c86b1fa6e4..8c460e39204 100644
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ClearCommand.java
@@ -2,22 +2,34 @@
import static java.util.Objects.requireNonNull;
+import java.util.List;
+
import seedu.address.model.AddressBook;
import seedu.address.model.Model;
+import seedu.address.model.application.InternshipApplication;
/**
- * Clears the address book.
+ * Clears the internship applications list.
*/
public class ClearCommand extends Command {
public static final String COMMAND_WORD = "clear";
- public static final String MESSAGE_SUCCESS = "Address book has been cleared!";
-
+ public static final String MESSAGE_SUCCESS = "All internship application has been cleared!";
+ public static final String MESSAGE_NULL = "There is nothing to clear!";
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.setAddressBook(new AddressBook());
+
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (lastShownList.size() == 0) {
+ return new CommandResult(MESSAGE_NULL);
+ }
+
+ model.addAllInternshipToCache(lastShownList);
+ model.setInternEase(new AddressBook());
+
return new CommandResult(MESSAGE_SUCCESS);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/address/logic/commands/CommandResult.java
index 92f900b7916..63479c5e64a 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/address/logic/commands/CommandResult.java
@@ -4,6 +4,8 @@
import java.util.Objects;
+import seedu.address.model.tag.TaskType;
+
/**
* Represents the result of a command execution.
*/
@@ -17,13 +19,21 @@ public class CommandResult {
/** The application should exit. */
private final boolean exit;
+
+ /** Reminder should be shown to user. */
+ private final boolean showReminder;
+
+ private TaskType type = TaskType.NONE;
+
+
/**
* Constructs a {@code CommandResult} with the specified fields.
*/
- public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
+ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, boolean showReminder) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
this.exit = exit;
+ this.showReminder = showReminder;
}
/**
@@ -31,7 +41,17 @@ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
* and other fields set to their default value.
*/
public CommandResult(String feedbackToUser) {
- this(feedbackToUser, false, false);
+ this(feedbackToUser, false, false, false);
+ }
+
+ /**
+ * Constructs a {@code CommandResult} with the specified {@code feedbackToUser},
+ * and set type to the command type.
+ */
+
+ public CommandResult(String feedbackToUser, TaskType type) {
+ this(feedbackToUser, false, false, false);
+ this.type = type;
}
public String getFeedbackToUser() {
@@ -42,10 +62,18 @@ public boolean isShowHelp() {
return showHelp;
}
+ public boolean isRemind() {
+ return showReminder;
+ }
+
public boolean isExit() {
return exit;
}
+ public TaskType getType() {
+ return type;
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -60,12 +88,18 @@ public boolean equals(Object other) {
CommandResult otherCommandResult = (CommandResult) other;
return feedbackToUser.equals(otherCommandResult.feedbackToUser)
&& showHelp == otherCommandResult.showHelp
- && exit == otherCommandResult.exit;
+ && exit == otherCommandResult.exit
+ && showReminder == otherCommandResult.showReminder;
}
@Override
public int hashCode() {
- return Objects.hash(feedbackToUser, showHelp, exit);
+ return Objects.hash(feedbackToUser, showHelp, exit, showReminder);
+ }
+
+ @Override
+ public String toString() {
+ return this.feedbackToUser;
}
}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
index 02fd256acba..9d34f8dd407 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
@@ -8,24 +8,29 @@
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;
+import seedu.address.model.application.InternshipApplication;
/**
- * Deletes a person identified using it's displayed index from the address book.
+ * Deletes an internship application identified by its displayed index from the internship applications list.
*/
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";
+ + ": Deletes the specified application from the list of internships applied.\n"
+ + "Deletes the application of internship at the specified INDEX.\n"
+ + "The index refers to the index number shown in the displayed internship list.\n"
+ + "Parameters: INDEX (must be a positive integer 1, 2, 3, ...)\n"
+ + "Example: " + COMMAND_WORD + " 2";
- public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
+ public static final String MESSAGE_DELETE_APPLICATION_SUCCESS = "Deleted Application: %1$s";
private final Index targetIndex;
+ /**
+ * Creates a DeleteCommand to delete the specified {@code targetIndex} internship applications.
+ */
public DeleteCommand(Index targetIndex) {
this.targetIndex = targetIndex;
}
@@ -33,15 +38,18 @@ public DeleteCommand(Index targetIndex) {
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
+ List lastShownList = model.getSortedFilteredInternshipList();
if (targetIndex.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
}
- Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
- model.deletePerson(personToDelete);
- return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete));
+ InternshipApplication internshipToDelete = lastShownList.get(targetIndex.getZeroBased());
+
+ model.deleteInternship(internshipToDelete);
+ model.addInternshipToCache(internshipToDelete);
+
+ return new CommandResult(String.format(MESSAGE_DELETE_APPLICATION_SUCCESS, internshipToDelete));
}
@Override
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
index 7e36114902f..c0ab4fbc549 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/seedu/address/logic/commands/EditCommand.java
@@ -1,12 +1,15 @@
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 static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB_TITLE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LOCATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NOTE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_QUALIFICATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REFLECTION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REVIEW;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
import java.util.Collections;
import java.util.HashSet;
@@ -19,87 +22,117 @@
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;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.contact.Contact;
+import seedu.address.model.documents.Documents;
/**
- * Edits the details of an existing person in the address book.
+ * Edits the details of an existing internship in the tracker.
*/
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. "
+ 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_NAME + "NAME] "
- + "[" + PREFIX_PHONE + "PHONE] "
- + "[" + PREFIX_EMAIL + "EMAIL] "
- + "[" + PREFIX_ADDRESS + "ADDRESS] "
- + "[" + PREFIX_TAG + "TAG]...\n"
+ + "[" + PREFIX_COMPANY_NAME + "COMPANY_NAME] "
+ + "[" + PREFIX_JOB_TITLE + "JOB_TITLE] "
+ + "[" + PREFIX_LOCATION + "LOCATION] "
+ + "[" + PREFIX_SALARY + "SALARY]"
+ + "[" + PREFIX_QUALIFICATION + "QUALIFICATION]... "
+ + "[" + PREFIX_PROGRAMMING_LANGUAGE + "PROGRAMMING_LANGUAGE]... "
+ + "[" + PREFIX_REVIEW + "REVIEW]... "
+ + "[" + PREFIX_NOTE + "NOTE]... "
+ + "[" + PREFIX_REFLECTION + "REFLECTION]... "
+ "Example: " + COMMAND_WORD + " 1 "
- + PREFIX_PHONE + "91234567 "
- + PREFIX_EMAIL + "johndoe@example.com";
+ + PREFIX_SALARY + "2000 SGD "
+ + PREFIX_NOTE + "JC senior working there";
- public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s";
+ public static final String MESSAGE_EDIT_INTERNSHIP_SUCCESS = "Edited Internship: %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.";
+ public static final String MESSAGE_DUPLICATE_INTERNSHIP = "This internship already exists in the tracker.";
private final Index index;
- private final EditPersonDescriptor editPersonDescriptor;
+ private final EditInternshipDescriptor editInternshipDescriptor;
/**
- * @param index of the person in the filtered person list to edit
- * @param editPersonDescriptor details to edit the person with
+ * @param index of the internship in the filtered internship list to edit
+ * @param editInternshipDescriptor details to edit the internship with
*/
- public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
+ public EditCommand(Index index, EditInternshipDescriptor editInternshipDescriptor) {
requireNonNull(index);
- requireNonNull(editPersonDescriptor);
+ requireNonNull(editInternshipDescriptor);
this.index = index;
- this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor);
+ this.editInternshipDescriptor = new EditInternshipDescriptor(editInternshipDescriptor);
}
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
+ List lastShownList = model.getSortedFilteredInternshipList();
if (index.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
}
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
+ InternshipApplication internshipToEdit = lastShownList.get(index.getZeroBased());
+ InternshipApplication editedInternship = createEditedInternship(internshipToEdit, editInternshipDescriptor);
- if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ if (!internshipToEdit.isSameApplication(editedInternship) && model.hasApplication(editedInternship)) {
+ throw new CommandException(MESSAGE_DUPLICATE_INTERNSHIP);
}
- model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson));
+ model.setApplication(internshipToEdit, editedInternship);
+ return new CommandResult(String.format(MESSAGE_EDIT_INTERNSHIP_SUCCESS, editedInternship));
}
/**
- * Creates and returns a {@code Person} with the details of {@code personToEdit}
- * edited with {@code editPersonDescriptor}.
+ * Creates and returns a {@code InternshipApplication} with the details of {@code personToEdit}
+ * edited with {@code editInternshipDescriptor}.
*/
- 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);
+ private static InternshipApplication createEditedInternship(InternshipApplication internshipToEdit,
+ EditInternshipDescriptor editInternshipDescriptor) {
+ assert internshipToEdit != null;
+
+ CompanyName updatedCompanyName = editInternshipDescriptor.getCompanyName()
+ .orElse(internshipToEdit.getCompanyName());
+ JobTitle updatedJobTitle = editInternshipDescriptor.getJobTitle().orElse(internshipToEdit.getJobTitle());
+ Location updatedLocation = editInternshipDescriptor.getLocation().orElse(internshipToEdit.getLocation());
+ Salary updatedSalary = editInternshipDescriptor.getSalary().orElse(internshipToEdit.getSalary());
+ Rating updatedRating = editInternshipDescriptor.getRating().orElse(internshipToEdit.getRating());
+ Set updatedQualifications = editInternshipDescriptor.getQualifications()
+ .orElse(internshipToEdit.getQualifications());
+ Set updatedProgrammingLanguages = editInternshipDescriptor.getProgrammingLanguages()
+ .orElse(internshipToEdit.getProgrammingLanguages());
+ Set updatedReviews = editInternshipDescriptor.getReviews().orElse(internshipToEdit.getReviews());
+ Set updatedNotes = editInternshipDescriptor.getNotes().orElse(internshipToEdit.getNotes());
+ Set updatedReflections = editInternshipDescriptor.getReflections()
+ .orElse(internshipToEdit.getReflections());
+ Contact contact = internshipToEdit.getContact();
+ InternshipStatus status = internshipToEdit.getStatus();
+ InterviewDate interviewDate = internshipToEdit.getInterviewDate();
+ Documents documents = internshipToEdit.getDocuments();
+ boolean isArchived = internshipToEdit.isArchived();
+
+ return new InternshipApplication(updatedCompanyName, updatedJobTitle, updatedReviews,
+ updatedProgrammingLanguages, updatedQualifications, updatedLocation, updatedSalary,
+ updatedNotes, updatedRating, updatedReflections, contact, status, isArchived, interviewDate,
+ documents);
}
@Override
@@ -117,88 +150,177 @@ public boolean equals(Object other) {
// state check
EditCommand e = (EditCommand) other;
return index.equals(e.index)
- && editPersonDescriptor.equals(e.editPersonDescriptor);
+ && editInternshipDescriptor.equals(e.editInternshipDescriptor);
}
/**
- * Stores the details to edit the person with. Each non-empty field value will replace the
- * corresponding field value of the person.
+ * 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 EditPersonDescriptor {
- private Name name;
- private Phone phone;
- private Email email;
- private Address address;
- private Set tags;
-
- public EditPersonDescriptor() {}
+ public static class EditInternshipDescriptor {
+ private CompanyName companyName;
+ private JobTitle jobTitle;
+ private Location location;
+ private Salary salary;
+ private Rating rating;
+ private Set qualifications;
+ private Set programmingLanguages;
+ private Set reviews;
+ private Set notes;
+ private Set reflections;
+
+ public EditInternshipDescriptor() {}
/**
* 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);
+ public EditInternshipDescriptor(EditInternshipDescriptor toCopy) {
+ setCompanyName(toCopy.companyName);
+ setJobTitle(toCopy.jobTitle);
+ setLocation(toCopy.location);
+ setSalary(toCopy.salary);
+ setRating(toCopy.rating);
+ setQualifications(toCopy.qualifications);
+ setProgrammingLanguages(toCopy.programmingLanguages);
+ setReviews(toCopy.reviews);
+ setNotes(toCopy.notes);
+ setReflections(toCopy.reflections);
}
/**
* Returns true if at least one field is edited.
*/
public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
+ return CollectionUtil.isAnyNonNull(companyName, jobTitle, location, salary, rating, qualifications,
+ programmingLanguages, reviews, notes, reflections);
+ }
+
+ public void setCompanyName(CompanyName companyName) {
+ this.companyName = companyName;
+ }
+
+ public Optional getCompanyName() {
+ return Optional.ofNullable(companyName);
}
- public void setName(Name name) {
- this.name = name;
+ public void setJobTitle(JobTitle jobTitle) {
+ this.jobTitle = jobTitle;
}
- public Optional getName() {
- return Optional.ofNullable(name);
+ public Optional getJobTitle() {
+ return Optional.ofNullable(jobTitle);
}
- public void setPhone(Phone phone) {
- this.phone = phone;
+ public void setLocation(Location location) {
+ this.location = location;
}
- public Optional getPhone() {
- return Optional.ofNullable(phone);
+ public Optional getLocation() {
+ return Optional.ofNullable(location);
}
- public void setEmail(Email email) {
- this.email = email;
+ public void setSalary(Salary salary) {
+ this.salary = salary;
}
- public Optional getEmail() {
- return Optional.ofNullable(email);
+ public Optional getSalary() {
+ return Optional.ofNullable(salary);
}
- public void setAddress(Address address) {
- this.address = address;
+ public void setRating(Rating rating) {
+ this.rating = rating;
}
- public Optional getAddress() {
- return Optional.ofNullable(address);
+ public Optional getRating() {
+ return Optional.ofNullable(rating);
}
/**
- * Sets {@code tags} to this object's {@code tags}.
- * A defensive copy of {@code tags} is used internally.
+ * Sets {@code qualifications} to this object's {@code qualifications}.
+ * A defensive copy of {@code qualifications} is used internally.
*/
- public void setTags(Set tags) {
- this.tags = (tags != null) ? new HashSet<>(tags) : null;
+ public void setQualifications(Set qualifications) {
+ this.qualifications = (qualifications != null) ? new HashSet<>(qualifications) : null;
}
/**
- * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
+ * Returns an unmodifiable qualification set, which throws {@code UnsupportedOperationException}
* if modification is attempted.
- * Returns {@code Optional#empty()} if {@code tags} is null.
+ * Returns {@code Optional#empty()} if {@code qualifications} is null.
+ */
+ public Optional> getQualifications() {
+ return (qualifications != null) ? Optional.of(Collections.unmodifiableSet(qualifications))
+ : Optional.empty();
+ }
+
+ /**
+ * Sets {@code programmingLanguages} to this object's {@code programmingLanguages}.
+ * A defensive copy of {@code programmingLanguages} is used internally.
*/
- public Optional> getTags() {
- return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
+ public void setProgrammingLanguages(Set programmingLanguages) {
+ this.programmingLanguages = (programmingLanguages != null) ? new HashSet<>(programmingLanguages) : null;
+ }
+
+ /**
+ * Returns an unmodifiable programmingLanguage set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ * Returns {@code Optional#empty()} if {@code programmingLanguages} is null.
+ */
+ public Optional> getProgrammingLanguages() {
+ return (programmingLanguages != null) ? Optional.of(Collections.unmodifiableSet(programmingLanguages))
+ : Optional.empty();
+ }
+
+ /**
+ * Sets {@code reviews} to this object's {@code reviews}.
+ * A defensive copy of {@code reviews} is used internally.
+ */
+ public void setReviews(Set reviews) {
+ this.reviews = (reviews != null) ? new HashSet<>(reviews) : null;
+ }
+
+ /**
+ * Returns an unmodifiable review set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ * Returns {@code Optional#empty()} if {@code reviews} is null.
+ */
+ public Optional> getReviews() {
+ return (reviews != null) ? Optional.of(Collections.unmodifiableSet(reviews)) : Optional.empty();
+ }
+
+ /**
+ * Sets {@code notes} to this object's {@code notes}.
+ * A defensive copy of {@code notes} is used internally.
+ */
+ public void setNotes(Set notes) {
+ this.notes = (notes != null) ? new HashSet<>(notes) : null;
+ }
+
+ /**
+ * Returns an unmodifiable note set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ * Returns {@code Optional#empty()} if {@code notes} is null.
+ */
+ public Optional> getNotes() {
+ return (notes != null) ? Optional.of(Collections.unmodifiableSet(notes)) : Optional.empty();
+ }
+
+ /**
+ * Sets {@code reflections} to this object's {@code reflections}.
+ * A defensive copy of {@code reflections} is used internally.
+ */
+ public void setReflections(Set reflections) {
+ this.reflections = (reflections != null) ? new HashSet<>(reflections) : null;
+ }
+
+ /**
+ * Returns an unmodifiable reflection set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ * Returns {@code Optional#empty()} if {@code reflections} is null.
+ */
+ public Optional> getReflections() {
+ return (reflections != null) ? Optional.of(Collections.unmodifiableSet(reflections)) : Optional.empty();
}
@Override
@@ -209,18 +331,23 @@ public boolean equals(Object other) {
}
// instanceof handles nulls
- if (!(other instanceof EditPersonDescriptor)) {
+ if (!(other instanceof EditInternshipDescriptor)) {
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());
+ EditInternshipDescriptor e = (EditInternshipDescriptor) other;
+
+ return getCompanyName().equals(e.getCompanyName())
+ && getJobTitle().equals(e.getJobTitle())
+ && getLocation().equals(e.getLocation())
+ && getSalary().equals(e.getSalary())
+ && getRating().equals(e.getRating())
+ && getQualifications().equals(e.getQualifications())
+ && getProgrammingLanguages().equals(e.getProgrammingLanguages())
+ && getReviews().equals(e.getReviews())
+ && getNotes().equals(e.getNotes())
+ && getReflections().equals(e.getReflections());
}
}
}
diff --git a/src/main/java/seedu/address/logic/commands/EditStatusCommand.java b/src/main/java/seedu/address/logic/commands/EditStatusCommand.java
new file mode 100644
index 00000000000..fb885fc60f2
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/EditStatusCommand.java
@@ -0,0 +1,109 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_STATUS;
+
+import java.util.List;
+import java.util.Set;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.contact.Contact;
+import seedu.address.model.documents.Documents;
+
+/**
+ * Edits the status of an application identified using it's displayed index from the list of internship applications.
+ */
+public class EditStatusCommand extends Command {
+
+ public static final String COMMAND_WORD = "edit_status";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Edits the status the specified application from the list of internships applied.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + PREFIX_STATUS + "STATUS (must be one of PENDING, RECEIVED, ACCEPTED, DECLINED or REJECTED)\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_STATUS + "NA";
+
+ public static final String MESSAGE_UPDATE_STATUS_SUCCESS = "Status of application updated: %1$s";
+
+ private final Index targetIndex;
+
+ private final InternshipStatus toUpdate;
+
+ /**
+ * @param targetIndex of the internship application to update status
+ * @param internshipStatus Internship status to update
+ */
+ public EditStatusCommand(Index targetIndex, InternshipStatus internshipStatus) {
+ requireNonNull(targetIndex);
+
+ this.targetIndex = targetIndex;
+ toUpdate = internshipStatus;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ InternshipApplication internshipToUpdateStatus = lastShownList.get(targetIndex.getZeroBased());
+ InternshipApplication updatedApplication = createdUpdatedApplication(internshipToUpdateStatus, toUpdate);
+
+ model.setApplication(internshipToUpdateStatus, updatedApplication);
+ return new CommandResult(String.format(MESSAGE_UPDATE_STATUS_SUCCESS, updatedApplication));
+ }
+
+ /**
+ * Creates and returns a {@code InternshipApplication} with the status of {@code InternshipStatus}
+ */
+ private static InternshipApplication createdUpdatedApplication(InternshipApplication internshipApplication,
+ InternshipStatus status) {
+ assert internshipApplication != null;
+
+ CompanyName companyName = internshipApplication.getCompanyName();
+ JobTitle jobTitle = internshipApplication.getJobTitle();
+ Set reviews = internshipApplication.getReviews();
+ Set programmingLanguages = internshipApplication.getProgrammingLanguages();
+ Set qualifications = internshipApplication.getQualifications();
+ Location location = internshipApplication.getLocation();
+ Salary salary = internshipApplication.getSalary();
+ Set notes = internshipApplication.getNotes();
+ Rating rating = internshipApplication.getRating();
+ Set reflections = internshipApplication.getReflections();
+ Contact contact = internshipApplication.getContact();
+ boolean isArchived = internshipApplication.isArchived();
+ InterviewDate interviewDate = internshipApplication.getInterviewDate();
+ Documents documents = internshipApplication.getDocuments();
+
+ return new InternshipApplication(companyName, jobTitle, reviews, programmingLanguages, qualifications, location,
+ salary, notes, rating, reflections, contact, status, isArchived, interviewDate, documents);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof EditStatusCommand // instanceof handles nulls
+ && targetIndex.equals(((EditStatusCommand) other).targetIndex)
+ && toUpdate.equals(((EditStatusCommand) other).toUpdate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java
index 3dd85a8ba90..2c970162daf 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java
@@ -3,17 +3,17 @@
import seedu.address.model.Model;
/**
- * Terminates the program.
+ * Terminates InternEase.
*/
public class ExitCommand extends Command {
public static final String COMMAND_WORD = "exit";
- public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ...";
+ public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting InternEase as requested ...";
@Override
public CommandResult execute(Model model) {
- return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
+ return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true, false);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
index d6b19b0a0de..7a3cd9a1d8d 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindCommand.java
@@ -1,26 +1,51 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_AFTER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_BEFORE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_FROM;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_TO;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_STATUS;
import seedu.address.commons.core.Messages;
import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.application.NameContainsKeywordsPredicate;
/**
- * Finds and lists all persons in address book whose name contains any of the argument keywords.
+ * Finds and lists all internship application in record whose CompanyName
+ * and/or JobTitle 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"
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": (1) Finds all internship applications whose "
+ + "CompanyName and/or JobTitle 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";
+ + "Example: " + COMMAND_WORD + " google software engineer intern\n"
+ + "(2) Finds all internship applications whose status matches the specified status (case-insensitive) "
+ + "and displays them as a list with index numbers.\n"
+ + "Parameters: " + "[" + PREFIX_STATUS + "STATUS]\n"
+ + "Example: " + COMMAND_WORD + " " + PREFIX_STATUS + "RECEIVED\n"
+ + "(3) Finds all internship applications whose interview date is before, after "
+ + "or between specified date(s)\n"
+ + "(i) Parameters: " + PREFIX_DATE_BEFORE + "DATE\n"
+ + "Example: " + COMMAND_WORD + " " + PREFIX_DATE_BEFORE + "12/31/2023 at 12:00 PM\n"
+ + "(ii) Parameters: " + PREFIX_DATE_AFTER + "DATE\n"
+ + "Example: " + COMMAND_WORD + " " + PREFIX_DATE_AFTER + "12/31/2023 at 12:00 PM\n"
+ + "(iii) Parameters: " + PREFIX_DATE_FROM + "START_DATE " + PREFIX_DATE_TO + "END_DATE\n"
+ + "Example: " + COMMAND_WORD + " " + PREFIX_DATE_FROM + "12/1/2023 at 1:00 PM "
+ + PREFIX_DATE_TO + "12/31/2023 at 7:00 PM";
private final NameContainsKeywordsPredicate predicate;
+ public FindCommand() {
+ this.predicate = null;
+ }
+
public FindCommand(NameContainsKeywordsPredicate predicate) {
this.predicate = predicate;
}
@@ -28,9 +53,10 @@ public FindCommand(NameContainsKeywordsPredicate predicate) {
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.updateFilteredPersonList(predicate);
+ model.updateFilteredInternshipList(predicate);
return new CommandResult(
- String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ String.format(Messages.MESSAGE_APPLICATION_LISTED_OVERVIEW,
+ model.getSortedFilteredInternshipList().size()));
}
@Override
diff --git a/src/main/java/seedu/address/logic/commands/FindDateCommand.java b/src/main/java/seedu/address/logic/commands/FindDateCommand.java
new file mode 100644
index 00000000000..c272414bdc3
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindDateCommand.java
@@ -0,0 +1,42 @@
+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.application.DatePredicate;
+
+/**
+ * Finds and lists all internship application in record whose {@code InterviewDate}
+ * is before, after or between specified date(s).
+ * The date specified is inclusive.
+ */
+public class FindDateCommand extends FindCommand {
+ private final DatePredicate predicate;
+
+ /**
+ * Creates an FindDateCommand to find the internship application with {@code InternshipDate}
+ * matches the given predicate.
+ *
+ * @param predicate The predicate containing date condition to be matched
+ */
+ public FindDateCommand(DatePredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredInternshipList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_APPLICATION_LISTED_OVERVIEW,
+ model.getSortedFilteredInternshipList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FindDateCommand // instanceof handles nulls
+ && predicate.equals(((FindDateCommand) other).predicate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindStatusCommand.java b/src/main/java/seedu/address/logic/commands/FindStatusCommand.java
new file mode 100644
index 00000000000..b99b0477634
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindStatusCommand.java
@@ -0,0 +1,41 @@
+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.application.StatusPredicate;
+
+/**
+ * Finds and lists all internship application in record whose status
+ * matches the specified keyword.
+ * Keyword matching is case insensitive.
+ */
+public class FindStatusCommand extends FindCommand {
+ private final StatusPredicate predicate;
+
+ /**
+ * Creates an FindStatusCommand to find the specified {@code InternshipStatus}.
+ *
+ * @param predicate The predicate containing status to be matched
+ */
+ public FindStatusCommand(StatusPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredInternshipList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_APPLICATION_LISTED_OVERVIEW,
+ model.getSortedFilteredInternshipList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FindStatusCommand // instanceof handles nulls
+ && predicate.equals(((FindStatusCommand) other).predicate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java
index bf824f91bd0..6a62830801a 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java
@@ -6,7 +6,6 @@
* Format full help instructions for every command for display.
*/
public class HelpCommand extends Command {
-
public static final String COMMAND_WORD = "help";
public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows program usage instructions.\n"
@@ -16,6 +15,6 @@ public class HelpCommand extends Command {
@Override
public CommandResult execute(Model model) {
- return new CommandResult(SHOWING_HELP_MESSAGE, true, false);
+ return new CommandResult(SHOWING_HELP_MESSAGE, true, false, false);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/ListArchivedCommand.java b/src/main/java/seedu/address/logic/commands/ListArchivedCommand.java
new file mode 100644
index 00000000000..89aca9448f1
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ListArchivedCommand.java
@@ -0,0 +1,33 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ARCHIVED_APPLICATIONS;
+
+import java.util.List;
+
+import seedu.address.model.Model;
+import seedu.address.model.application.InternshipApplication;
+
+/**
+ * Lists all internship applications which are archived in the list of internship applications to the user.
+ */
+public class ListArchivedCommand extends Command {
+
+ public static final String COMMAND_WORD = "list_archived";
+
+ public static final String MESSAGE_SUCCESS = "Listed all archived applications";
+ public static final String MESSAGE_NO_APPLICATIONS = "No archived applications at the moment";
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredInternshipList(PREDICATE_SHOW_ARCHIVED_APPLICATIONS);
+ List lastShownList = model.getSortedFilteredInternshipList();
+ if (lastShownList.size() > 0) {
+ return new CommandResult(MESSAGE_SUCCESS);
+ } else {
+ return new CommandResult(MESSAGE_NO_APPLICATIONS);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
index 84be6ad2596..76453983c29 100644
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ListCommand.java
@@ -1,24 +1,33 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ONGOING_APPLICATIONS;
+
+import java.util.List;
import seedu.address.model.Model;
+import seedu.address.model.application.InternshipApplication;
/**
- * Lists all persons in the address book to the user.
+ * Lists all internship applications 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";
+ public static final String MESSAGE_SUCCESS = "Listed all applications";
+ public static final String MESSAGE_NO_APPLICATIONS = "No active applications at the moment";
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(MESSAGE_SUCCESS);
+ model.updateFilteredInternshipList(PREDICATE_SHOW_ONGOING_APPLICATIONS);
+ List lastShownList = model.getSortedFilteredInternshipList();
+ if (lastShownList.size() > 0) {
+ return new CommandResult(MESSAGE_SUCCESS);
+ } else {
+ return new CommandResult(MESSAGE_NO_APPLICATIONS);
+ }
}
}
diff --git a/src/main/java/seedu/address/logic/commands/RemindCommand.java b/src/main/java/seedu/address/logic/commands/RemindCommand.java
new file mode 100644
index 00000000000..d6b095d07ae
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/RemindCommand.java
@@ -0,0 +1,17 @@
+package seedu.address.logic.commands;
+
+import seedu.address.model.Model;
+
+/**
+ * Displays reminder for upcoming interview.
+ */
+public class RemindCommand extends Command {
+ public static final String COMMAND_WORD = "remind";
+
+ public static final String SHOWING_REMINDER_MESSAGE = "Opened reminder window.";
+
+ @Override
+ public CommandResult execute(Model model) {
+ return new CommandResult(SHOWING_REMINDER_MESSAGE, false, false, true);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/RevertAllCommand.java b/src/main/java/seedu/address/logic/commands/RevertAllCommand.java
new file mode 100644
index 00000000000..6994c14a4ac
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/RevertAllCommand.java
@@ -0,0 +1,35 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.address.model.Model;
+import seedu.address.model.application.InternshipApplication;
+
+/**
+ * Reverts all deleted or cleared internship applications that are stored in the cache list for current session only.
+ */
+public class RevertAllCommand extends Command {
+
+ public static final String COMMAND_WORD = "revert_all";
+
+ public static final String MESSAGE_SUCCESS = "All cleared internship applications are reverted!";
+ public static final String MESSAGE_NO_APPLICATIONS = "No applications at the moment";
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+
+ List cacheList = model.getCachedInternshipList();
+
+ if (cacheList.size() > 0) {
+ model.setEmptyInternshipCacheList();
+ model.addApplications(cacheList);
+ return new CommandResult(MESSAGE_SUCCESS);
+ } else {
+ return new CommandResult(MESSAGE_NO_APPLICATIONS);
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/RevertCommand.java b/src/main/java/seedu/address/logic/commands/RevertCommand.java
new file mode 100644
index 00000000000..a1d2ef6b49d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/RevertCommand.java
@@ -0,0 +1,44 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.address.model.Model;
+import seedu.address.model.application.InternshipApplication;
+
+/**
+ * Reverts a most recently deleted or cleared internship application stored in the cache list for current session only.
+ */
+public class RevertCommand extends Command {
+
+ public static final String COMMAND_WORD = "revert";
+
+ public static final String MESSAGE_SUCCESS = "Previous deletion of internship application is reverted: %1$s";
+ public static final String MESSAGE_NO_APPLICATIONS = "No applications at the moment";
+ public static final String MESSAGE_DUPLICATE_APPLICATION = "This internship application "
+ + "already exists in the tracker";
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+
+ List cacheList = model.getCachedInternshipList();
+
+ if (cacheList.size() > 0) {
+ InternshipApplication application = model.getAndRemoveCachedApplication();
+ return hasApplication(model, application);
+ } else {
+ return new CommandResult(MESSAGE_NO_APPLICATIONS);
+ }
+ }
+
+ private CommandResult hasApplication(Model model, InternshipApplication application) {
+ if (model.hasApplication(application)) {
+ return new CommandResult(MESSAGE_DUPLICATE_APPLICATION);
+ } else {
+ model.addApplication(application);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, application));
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/SortCommand.java b/src/main/java/seedu/address/logic/commands/SortCommand.java
new file mode 100644
index 00000000000..4d6d23c821c
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/SortCommand.java
@@ -0,0 +1,66 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB_TITLE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_STATUS;
+
+import java.util.Comparator;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.logic.parser.Prefix;
+import seedu.address.model.Model;
+import seedu.address.model.application.InternshipApplication;
+
+/**
+ * Sorts and lists all internship application by any one of the following attributes: CompanyName,
+ * JobTitle, Status, InterviewDate in ascending order.
+ */
+public class SortCommand extends Command {
+
+ public static final String COMMAND_WORD = "sort";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Sorts the list of internship applications"
+ + "by ascending order. Exactly one parameter should be specified. "
+ + "If the value is not present, it will be placed at the end of the list.\n"
+ + "Parameters: "
+ + "[" + PREFIX_COMPANY_NAME + "COMPANY_NAME] "
+ + "[" + PREFIX_JOB_TITLE + "JOB_TITLE] "
+ + "[" + PREFIX_STATUS + "STATUS] "
+ + "[" + PREFIX_DATE + "INTERVIEW_DATE]\n"
+ + "Example: " + COMMAND_WORD + " " + PREFIX_DATE;
+
+ public static final Prefix[] PREFIXES_SUPPORTED = {
+ PREFIX_COMPANY_NAME, PREFIX_JOB_TITLE, PREFIX_STATUS, PREFIX_DATE
+ };
+
+ private final Comparator comparator;
+
+ /**
+ * Creates a SortCommand with comparator to sort the list of internship application.
+ *
+ * @param comparator Comparator used to sort the list
+ */
+ public SortCommand(Comparator comparator) {
+ requireNonNull(comparator);
+ this.comparator = comparator;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateSortedFilteredInternshipList(comparator);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_APPLICATION_LISTED_OVERVIEW,
+ model.getSortedFilteredInternshipList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof SortCommand // instanceof handles nulls
+ && comparator.equals(((SortCommand) other).comparator)); // state check
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/commands/UnarchiveCommand.java b/src/main/java/seedu/address/logic/commands/UnarchiveCommand.java
new file mode 100644
index 00000000000..9f0e993c4eb
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/UnarchiveCommand.java
@@ -0,0 +1,113 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ONGOING_APPLICATIONS;
+
+import java.util.List;
+import java.util.Set;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.contact.Contact;
+import seedu.address.model.documents.Documents;
+
+/**
+ * Unarchives an internship application identified using it's displayed index from the list of internship applications.
+ */
+public class UnarchiveCommand extends Command {
+
+ public static final String COMMAND_WORD = "unarchive";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Unarchives the specified application from the list of internships applied.\n"
+ + "Unarchives the application of internship at the specified INDEX.\n"
+ + "The index refers to the index number shown in the displayed internship list.\n"
+ + "Parameters: INDEX (must be a positive integer 1, 2, 3, ...)\n"
+ + "Example: " + COMMAND_WORD + " 2";
+
+ public static final String MESSAGE_UNARCHIVE_APPLICATION_SUCCESS = "Unarchived Application: %1$s";
+ public static final String MESSAGE_APPLICATION_NOT_ARCHIVED = "Application is not currently archived!";
+
+ private final Index targetIndex;
+
+ /**
+ * Creates an UnarchiveCommand to unarchive the specified {@code targetIndex} internship
+ *
+ * @param targetIndex of the internship application to unarchive
+ */
+ public UnarchiveCommand(Index targetIndex) {
+ requireNonNull(targetIndex);
+
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ InternshipApplication internshipToUnarchive = lastShownList.get(targetIndex.getZeroBased());
+
+ if (!internshipToUnarchive.isArchived()) {
+ throw new CommandException(MESSAGE_APPLICATION_NOT_ARCHIVED);
+ }
+
+ InternshipApplication archivedApplication = createdUnarchivedApplication(internshipToUnarchive);
+
+ model.setApplication(internshipToUnarchive, archivedApplication);
+ model.updateFilteredInternshipList(PREDICATE_SHOW_ONGOING_APPLICATIONS);
+ return new CommandResult(String.format(MESSAGE_UNARCHIVE_APPLICATION_SUCCESS, archivedApplication));
+ }
+
+ /**
+ * Creates and returns an archived {@code InternshipApplication}
+ */
+ private static InternshipApplication createdUnarchivedApplication(InternshipApplication internshipApplication) {
+ assert internshipApplication != null;
+
+ CompanyName companyName = internshipApplication.getCompanyName();
+ JobTitle jobTitle = internshipApplication.getJobTitle();
+ Set reviews = internshipApplication.getReviews();
+ Set programmingLanguages = internshipApplication.getProgrammingLanguages();
+ Set qualifications = internshipApplication.getQualifications();
+ Location location = internshipApplication.getLocation();
+ Salary salary = internshipApplication.getSalary();
+ Set notes = internshipApplication.getNotes();
+ Rating rating = internshipApplication.getRating();
+ Set reflections = internshipApplication.getReflections();
+ Contact contact = internshipApplication.getContact();
+ InternshipStatus status = internshipApplication.getStatus();
+ InterviewDate interviewDate = internshipApplication.getInterviewDate();
+ Documents documents = internshipApplication.getDocuments();
+
+ return new InternshipApplication(companyName, jobTitle, reviews, programmingLanguages, qualifications, location,
+ salary, notes, rating, reflections, contact, status, false, interviewDate,
+ documents);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof UnarchiveCommand // instanceof handles nulls
+ && targetIndex.equals(((UnarchiveCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/contact/AddContactCommand.java b/src/main/java/seedu/address/logic/commands/contact/AddContactCommand.java
new file mode 100644
index 00000000000..2c9f02788e4
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/contact/AddContactCommand.java
@@ -0,0 +1,115 @@
+package seedu.address.logic.commands.contact;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+
+import java.util.List;
+import java.util.Set;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.contact.Contact;
+import seedu.address.model.documents.Documents;
+
+/**
+ * Adds a contact to an application identified using it's displayed index from the list of internship applications.
+ */
+public class AddContactCommand extends Command {
+
+ public static final String COMMAND_WORD = "add_contact";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Adds contact details to the specified application from the list of internships applied.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + PREFIX_PHONE + "PHONE "
+ + PREFIX_EMAIL + "EMAIL "
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_PHONE + "98765432 "
+ + PREFIX_EMAIL + "johnd@example.com ";
+
+ public static final String MESSAGE_ADD_CONTACT_SUCCESS = "Contact details added to application: %1$s";
+
+ private final Index targetIndex;
+
+ private final Contact toAdd;
+
+ /**
+ * @param targetIndex of the internship application to add contact details
+ * @param contact Contact to add
+ */
+ public AddContactCommand(Index targetIndex, Contact contact) {
+ requireNonNull(targetIndex);
+
+ this.targetIndex = targetIndex;
+ toAdd = contact;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ InternshipApplication internshipToAddContact = lastShownList.get(targetIndex.getZeroBased());
+ InternshipApplication internshipWithContact = createInternshipWithContact(internshipToAddContact, toAdd);
+
+ model.setApplication(internshipToAddContact, internshipWithContact);
+ return new CommandResult(String.format(MESSAGE_ADD_CONTACT_SUCCESS, internshipToAddContact + "\n" + toAdd));
+ }
+
+ /**
+ * Creates and returns a {@code InternshipApplication} with the details of {@code internshipToAddContact}
+ * added with the contact {@code toAdd}.
+ */
+ private static InternshipApplication createInternshipWithContact(InternshipApplication internshipToAddContact,
+ Contact contact) {
+ assert internshipToAddContact != null;
+
+ CompanyName companyName = internshipToAddContact.getCompanyName();
+ JobTitle jobTitle = internshipToAddContact.getJobTitle();
+ Set reviews = internshipToAddContact.getReviews();
+ Set programmingLanguages = internshipToAddContact.getProgrammingLanguages();
+ Set qualifications = internshipToAddContact.getQualifications();
+ Location location = internshipToAddContact.getLocation();
+ Salary salary = internshipToAddContact.getSalary();
+ Set notes = internshipToAddContact.getNotes();
+ Rating rating = internshipToAddContact.getRating();
+ Set reflections = internshipToAddContact.getReflections();
+ InternshipStatus status = internshipToAddContact.getStatus();
+ boolean isArchived = internshipToAddContact.isArchived();
+ InterviewDate interviewDate = internshipToAddContact.getInterviewDate();
+ Documents documents = internshipToAddContact.getDocuments();
+
+ return new InternshipApplication(companyName, jobTitle, reviews, programmingLanguages, qualifications, location,
+ salary, notes, rating, reflections, contact, status, isArchived, interviewDate, documents);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddContactCommand // instanceof handles nulls
+ && targetIndex.equals(((AddContactCommand) other).targetIndex)
+ && toAdd.equals(((AddContactCommand) other).toAdd)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/contact/DeleteContactCommand.java b/src/main/java/seedu/address/logic/commands/contact/DeleteContactCommand.java
new file mode 100644
index 00000000000..72de20f4cf9
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/contact/DeleteContactCommand.java
@@ -0,0 +1,113 @@
+package seedu.address.logic.commands.contact;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+import java.util.Set;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.documents.Documents;
+
+/**
+ * Delete the contact details of an application identified using it's displayed index
+ * from the list of internship applications.
+ */
+public class DeleteContactCommand extends Command {
+
+ public static final String COMMAND_WORD = "delete_contact";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the contact details of of the specified application from the "
+ + "list of internships applied.\n"
+ + "Parameters: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1 ";
+
+ public static final String MESSAGE_CONTACT_NOT_FOUND =
+ "No contact added";
+
+ public static final String MESSAGE_DELETE_CONTACT_SUCCESS =
+ "Contact deleted from application: %1$s";
+
+ private final Index targetIndex;
+
+ /**
+ * @param targetIndex of the internship application to delete contact
+ */
+ public DeleteContactCommand(Index targetIndex) {
+ requireNonNull(targetIndex);
+
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ InternshipApplication internshipToDeleteContact = lastShownList.get(targetIndex.getZeroBased());
+ if (internshipToDeleteContact.getContact() == null) {
+ throw new CommandException(MESSAGE_CONTACT_NOT_FOUND);
+ }
+ InternshipApplication internshipWithContactDeleted =
+ createInternshipWithContactDeleted(internshipToDeleteContact);
+
+ model.setApplication(internshipToDeleteContact, internshipWithContactDeleted);
+ return new CommandResult(String.format(MESSAGE_DELETE_CONTACT_SUCCESS, internshipToDeleteContact));
+ }
+
+ /**
+ * Creates and returns a {@code InternshipApplication} with the details of {@code internshipToDeleteDocuments}
+ * and contact removed.
+ */
+ private static InternshipApplication createInternshipWithContactDeleted(
+ InternshipApplication internshipToDeleteContact) {
+ assert internshipToDeleteContact != null;
+
+ CompanyName companyName = internshipToDeleteContact.getCompanyName();
+ JobTitle jobTitle = internshipToDeleteContact.getJobTitle();
+ Set reviews = internshipToDeleteContact.getReviews();
+ Set programmingLanguages = internshipToDeleteContact.getProgrammingLanguages();
+ Set qualifications = internshipToDeleteContact.getQualifications();
+ Location location = internshipToDeleteContact.getLocation();
+ Salary salary = internshipToDeleteContact.getSalary();
+ Set notes = internshipToDeleteContact.getNotes();
+ Rating rating = internshipToDeleteContact.getRating();
+ Set reflections = internshipToDeleteContact.getReflections();
+ InternshipStatus status = internshipToDeleteContact.getStatus();
+ boolean isArchived = internshipToDeleteContact.isArchived();
+ InterviewDate interviewDate = internshipToDeleteContact.getInterviewDate();
+ Documents documents = internshipToDeleteContact.getDocuments();
+
+ return new InternshipApplication(companyName, jobTitle, reviews, programmingLanguages, qualifications, location,
+ salary, notes, rating, reflections, null, status, isArchived, interviewDate, documents);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteContactCommand // instanceof handles nulls
+ && targetIndex.equals(((DeleteContactCommand) other).targetIndex));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/contact/EditContactCommand.java b/src/main/java/seedu/address/logic/commands/contact/EditContactCommand.java
new file mode 100644
index 00000000000..ac9bc701602
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/contact/EditContactCommand.java
@@ -0,0 +1,203 @@
+package seedu.address.logic.commands.contact;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+
+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.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.contact.Contact;
+import seedu.address.model.contact.Email;
+import seedu.address.model.contact.Phone;
+import seedu.address.model.documents.Documents;
+
+/**
+ * Edits the contact details of an existing application in the list of internship applications.
+ */
+public class EditContactCommand extends Command {
+ public static final String COMMAND_WORD = "edit_contact";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the contact of the application identified "
+ + "by the index number used in the internship application list. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "[" + PREFIX_PHONE + "PHONE] "
+ + "[" + PREFIX_EMAIL + "EMAIL]\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_PHONE + "98765432 "
+ + PREFIX_EMAIL + "johndoe@example.com";
+
+ public static final String MESSAGE_EDIT_CONTACT_SUCCESS = "Edited contact details for application: %1$s";
+ public static final String MESSAGE_CONTACT_NOT_FOUND =
+ "No contact added";
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+
+ private final Index index;
+ private final EditContactDescriptor editContactDescriptor;
+
+ /**
+ * @param index of the application in the filtered internship application list to edit
+ * @param editContactDescriptor details to edit the contact with
+ */
+ public EditContactCommand(Index index, EditContactDescriptor editContactDescriptor) {
+ requireNonNull(index);
+ requireNonNull(editContactDescriptor);
+
+ this.index = index;
+ this.editContactDescriptor = new EditContactDescriptor(editContactDescriptor);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ InternshipApplication internshipToUpdateContact = lastShownList.get(index.getZeroBased());
+ if (internshipToUpdateContact.getContact() == null) {
+ throw new CommandException(MESSAGE_CONTACT_NOT_FOUND);
+ }
+ InternshipApplication internshipWithUpdatedContact =
+ createInternshipWithUpdatedContact(internshipToUpdateContact, editContactDescriptor);
+
+ model.setApplication(internshipToUpdateContact, internshipWithUpdatedContact);
+ return new CommandResult(String.format(MESSAGE_EDIT_CONTACT_SUCCESS, internshipWithUpdatedContact));
+ }
+
+ /**
+ * Creates and returns a {@code InternshipApplication} with the details of {@code internshipToUpdateContact}
+ * and contact edited with {@code editContactDescriptor}.
+ */
+ private static InternshipApplication createInternshipWithUpdatedContact(
+ InternshipApplication internshipToUpdateContact, EditContactDescriptor editContactDescriptor) {
+ assert internshipToUpdateContact != null;
+
+ CompanyName companyName = internshipToUpdateContact.getCompanyName();
+ JobTitle jobTitle = internshipToUpdateContact.getJobTitle();
+ Set reviews = internshipToUpdateContact.getReviews();
+ Set programmingLanguages = internshipToUpdateContact.getProgrammingLanguages();
+ Set qualifications = internshipToUpdateContact.getQualifications();
+ Location location = internshipToUpdateContact.getLocation();
+ Salary salary = internshipToUpdateContact.getSalary();
+ Set notes = internshipToUpdateContact.getNotes();
+ Rating rating = internshipToUpdateContact.getRating();
+ Set reflections = internshipToUpdateContact.getReflections();
+ Phone phone = editContactDescriptor.getPhone()
+ .orElse(internshipToUpdateContact.getContact().getPhone());
+ Email email = editContactDescriptor.getEmail()
+ .orElse(internshipToUpdateContact.getContact().getEmail());
+ Contact newContact = new Contact(phone, email);
+ InternshipStatus status = internshipToUpdateContact.getStatus();
+ boolean isArchived = internshipToUpdateContact.isArchived();
+ InterviewDate interviewDate = internshipToUpdateContact.getInterviewDate();
+ Documents documents = internshipToUpdateContact.getDocuments();
+
+ return new InternshipApplication(companyName, jobTitle, reviews, programmingLanguages, qualifications, location,
+ salary, notes, rating, reflections, newContact, status, isArchived, interviewDate, documents);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditContactCommand)) {
+ return false;
+ }
+
+ // state check
+ EditContactCommand e = (EditContactCommand) other;
+ return index.equals(e.index)
+ && editContactDescriptor.equals(e.editContactDescriptor);
+ }
+
+ /**
+ * Stores the details to edit the contact with. Each non-empty field value will replace the
+ * corresponding field value of the contact.
+ */
+ public static class EditContactDescriptor {
+ private Phone phone;
+ private Email email;
+
+ public EditContactDescriptor() {}
+
+ /**
+ * Copy constructor.
+ * A defensive copy of {@code tags} is used internally.
+ */
+ public EditContactDescriptor(EditContactDescriptor toCopy) {
+ setPhone(toCopy.phone);
+ setEmail(toCopy.email);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(phone, email);
+ }
+
+ 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);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditContactDescriptor)) {
+ return false;
+ }
+
+ // state check
+ EditContactDescriptor e = (EditContactDescriptor) other;
+
+ return getPhone().equals(e.getPhone())
+ && getEmail().equals(e.getEmail());
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/documents/AddDocumentsCommand.java b/src/main/java/seedu/address/logic/commands/documents/AddDocumentsCommand.java
new file mode 100644
index 00000000000..7d54548fdd2
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/documents/AddDocumentsCommand.java
@@ -0,0 +1,118 @@
+package seedu.address.logic.commands.documents;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COVER_LETTER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_RESUME;
+
+import java.util.List;
+import java.util.Set;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.contact.Contact;
+import seedu.address.model.documents.Documents;
+
+/**
+ * Adds links to a resume and/or cover letter to an application identified using it's displayed index
+ * from the list of internship applications.
+ */
+public class AddDocumentsCommand extends Command {
+
+ public static final String COMMAND_WORD = "add_docs";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Adds link to a resume and/or cover letter to the specified application from the "
+ + "list of internships applied.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + PREFIX_RESUME + "RESUME "
+ + PREFIX_COVER_LETTER + "COVER_LETTER\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_RESUME + "https://docs.google.com/document/d/EXAMPLE_RESUME/edit "
+ + PREFIX_COVER_LETTER + "https://docs.google.com/document/d/EXAMPLE_COVER_LETTER/edit";
+
+ public static final String MESSAGE_ADD_DOCUMENTS_SUCCESS = "Resume and/or cover letter added to application: %1$s";
+
+ private final Index targetIndex;
+
+
+ private final Documents toAdd;
+
+ /**
+ * @param targetIndex of the internship application to add documents
+ * @param documents documents to be added
+ */
+ public AddDocumentsCommand(Index targetIndex, Documents documents) {
+ requireNonNull(targetIndex);
+
+ this.targetIndex = targetIndex;
+ this.toAdd = documents;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ InternshipApplication internshipToAddDocuments = lastShownList.get(targetIndex.getZeroBased());
+ InternshipApplication internshipWithDocuments = createInternshipWithDocuments(internshipToAddDocuments, toAdd);
+
+ model.setApplication(internshipToAddDocuments, internshipWithDocuments);
+ return new CommandResult(String.format(MESSAGE_ADD_DOCUMENTS_SUCCESS, internshipToAddDocuments + "\n" + toAdd));
+ }
+
+ /**
+ * Creates and returns a {@code InternshipApplication} with the details of {@code internshipToAddDocuments}
+ * added with the documents {@code toAdd}.
+ */
+ private static InternshipApplication createInternshipWithDocuments(InternshipApplication internshipToAddDocuments,
+ Documents documents) {
+ assert internshipToAddDocuments != null;
+
+ CompanyName companyName = internshipToAddDocuments.getCompanyName();
+ JobTitle jobTitle = internshipToAddDocuments.getJobTitle();
+ Set reviews = internshipToAddDocuments.getReviews();
+ Set programmingLanguages = internshipToAddDocuments.getProgrammingLanguages();
+ Set qualifications = internshipToAddDocuments.getQualifications();
+ Location location = internshipToAddDocuments.getLocation();
+ Salary salary = internshipToAddDocuments.getSalary();
+ Set notes = internshipToAddDocuments.getNotes();
+ Rating rating = internshipToAddDocuments.getRating();
+ Set reflections = internshipToAddDocuments.getReflections();
+ Contact contact = internshipToAddDocuments.getContact();
+ boolean isArchived = internshipToAddDocuments.isArchived();
+ InternshipStatus status = internshipToAddDocuments.getStatus();
+ InterviewDate interviewDate = internshipToAddDocuments.getInterviewDate();
+
+ return new InternshipApplication(companyName, jobTitle, reviews, programmingLanguages, qualifications, location,
+ salary, notes, rating, reflections, contact, status, isArchived, interviewDate, documents);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddDocumentsCommand // instanceof handles nulls
+ && targetIndex.equals(((AddDocumentsCommand) other).targetIndex)
+ && toAdd.equals(((AddDocumentsCommand) other).toAdd)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/documents/DeleteDocumentsCommand.java b/src/main/java/seedu/address/logic/commands/documents/DeleteDocumentsCommand.java
new file mode 100644
index 00000000000..a29525daef0
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/documents/DeleteDocumentsCommand.java
@@ -0,0 +1,113 @@
+package seedu.address.logic.commands.documents;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+import java.util.Set;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.contact.Contact;
+
+/**
+ * Delete links to the resume and/or cover letter of an application identified using it's displayed index
+ * from the list of internship applications.
+ */
+public class DeleteDocumentsCommand extends Command {
+
+ public static final String COMMAND_WORD = "delete_docs";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes link to the resume and/or cover letter of the specified application from the "
+ + "list of internships applied.\n"
+ + "Parameters: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1 ";
+
+ public static final String MESSAGE_DOCUMENTS_NOT_FOUND =
+ "No resume and/or cover letter added";
+
+ public static final String MESSAGE_DELETE_DOCUMENTS_SUCCESS =
+ "Resume and/or cover letter deleted from application: %1$s";
+
+ private final Index targetIndex;
+
+ /**
+ * @param targetIndex of the internship application to delete documents
+ */
+ public DeleteDocumentsCommand(Index targetIndex) {
+ requireNonNull(targetIndex);
+
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ InternshipApplication internshipToDeleteDocuments = lastShownList.get(targetIndex.getZeroBased());
+ if (internshipToDeleteDocuments.getDocuments() == null) {
+ throw new CommandException(MESSAGE_DOCUMENTS_NOT_FOUND);
+ }
+ InternshipApplication internshipWithDocumentsDeleted =
+ createInternshipWithDocumentsDeleted(internshipToDeleteDocuments);
+
+ model.setApplication(internshipToDeleteDocuments, internshipWithDocumentsDeleted);
+ return new CommandResult(String.format(MESSAGE_DELETE_DOCUMENTS_SUCCESS, internshipToDeleteDocuments));
+ }
+
+ /**
+ * Creates and returns a {@code InternshipApplication} with the details of {@code internshipToDeleteDocuments}
+ * and documents removed.
+ */
+ private static InternshipApplication createInternshipWithDocumentsDeleted(
+ InternshipApplication internshipToDeleteDocuments) {
+ assert internshipToDeleteDocuments != null;
+
+ CompanyName companyName = internshipToDeleteDocuments.getCompanyName();
+ JobTitle jobTitle = internshipToDeleteDocuments.getJobTitle();
+ Set reviews = internshipToDeleteDocuments.getReviews();
+ Set programmingLanguages = internshipToDeleteDocuments.getProgrammingLanguages();
+ Set qualifications = internshipToDeleteDocuments.getQualifications();
+ Location location = internshipToDeleteDocuments.getLocation();
+ Salary salary = internshipToDeleteDocuments.getSalary();
+ Set notes = internshipToDeleteDocuments.getNotes();
+ Rating rating = internshipToDeleteDocuments.getRating();
+ Set reflections = internshipToDeleteDocuments.getReflections();
+ Contact contact = internshipToDeleteDocuments.getContact();
+ InternshipStatus status = internshipToDeleteDocuments.getStatus();
+ boolean isArchived = internshipToDeleteDocuments.isArchived();
+ InterviewDate interviewDate = internshipToDeleteDocuments.getInterviewDate();
+
+ return new InternshipApplication(companyName, jobTitle, reviews, programmingLanguages, qualifications, location,
+ salary, notes, rating, reflections, contact, status, isArchived, interviewDate, null);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteDocumentsCommand // instanceof handles nulls
+ && targetIndex.equals(((DeleteDocumentsCommand) other).targetIndex));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/documents/EditDocumentsCommand.java b/src/main/java/seedu/address/logic/commands/documents/EditDocumentsCommand.java
new file mode 100644
index 00000000000..c8a72ca1c89
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/documents/EditDocumentsCommand.java
@@ -0,0 +1,201 @@
+package seedu.address.logic.commands.documents;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COVER_LETTER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_RESUME;
+
+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.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.contact.Contact;
+import seedu.address.model.documents.CoverLetterLink;
+import seedu.address.model.documents.Documents;
+import seedu.address.model.documents.ResumeLink;
+
+/**
+ * Edits links to the resume and/or cover letter of an application identified using it's displayed index
+ * from the list of internship applications.
+ */
+public class EditDocumentsCommand extends Command {
+
+ public static final String COMMAND_WORD = "edit_docs";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Edits links to the resume and/or cover letter of the specified application from the "
+ + "list of internships applied.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "[" + PREFIX_RESUME + "RESUME] "
+ + "[" + PREFIX_COVER_LETTER + "COVER_LETTER]\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_RESUME + "https://docs.google.com/document/d/EXAMPLE_RESUME/edit "
+ + PREFIX_COVER_LETTER + "https://docs.google.com/document/d/EXAMPLE_COVER_LETTER/edit";
+
+ public static final String MESSAGE_DOCUMENTS_NOT_FOUND =
+ "No resume and/or cover letter added";
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+ public static final String MESSAGE_EDIT_DOCUMENTS_SUCCESS =
+ "Resume and/or cover letter updated for application: %1$s";
+
+ private final Index targetIndex;
+
+
+ private final EditDocumentsDescriptor editDocumentsDescriptor;
+
+ /**
+ * @param targetIndex of the internship application to edit documents
+ * @param editDocumentsDescriptor details to edit the documents with
+ */
+ public EditDocumentsCommand(Index targetIndex, EditDocumentsDescriptor editDocumentsDescriptor) {
+ requireNonNull(targetIndex);
+
+ this.targetIndex = targetIndex;
+ this.editDocumentsDescriptor = editDocumentsDescriptor;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getSortedFilteredInternshipList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_APPLICATION_DISPLAYED_INDEX);
+ }
+
+ InternshipApplication internshipToEditDocuments = lastShownList.get(targetIndex.getZeroBased());
+ if (internshipToEditDocuments.getDocuments() == null) {
+ throw new CommandException(MESSAGE_DOCUMENTS_NOT_FOUND);
+ }
+ InternshipApplication internshipWithUpdatedDocuments =
+ createInternshipWithUpdatedDocuments(internshipToEditDocuments, editDocumentsDescriptor);
+
+ model.setApplication(internshipToEditDocuments, internshipWithUpdatedDocuments);
+ return new CommandResult(String.format(MESSAGE_EDIT_DOCUMENTS_SUCCESS, internshipToEditDocuments));
+ }
+
+ /**
+ * Creates and returns a {@code InternshipApplication} with the details of {@code internshipToEditDocuments}
+ * edited with {@code editDocumentsDescriptor}.
+ */
+ private static InternshipApplication createInternshipWithUpdatedDocuments(
+ InternshipApplication internshipToEditDocuments,
+ EditDocumentsDescriptor editDocumentsDescriptor) {
+
+ assert internshipToEditDocuments != null;
+
+ CompanyName companyName = internshipToEditDocuments.getCompanyName();
+ JobTitle jobTitle = internshipToEditDocuments.getJobTitle();
+ Set reviews = internshipToEditDocuments.getReviews();
+ Set programmingLanguages = internshipToEditDocuments.getProgrammingLanguages();
+ Set qualifications = internshipToEditDocuments.getQualifications();
+ Location location = internshipToEditDocuments.getLocation();
+ Salary salary = internshipToEditDocuments.getSalary();
+ Set notes = internshipToEditDocuments.getNotes();
+ Rating rating = internshipToEditDocuments.getRating();
+ Set reflections = internshipToEditDocuments.getReflections();
+ Contact contact = internshipToEditDocuments.getContact();
+ InternshipStatus status = internshipToEditDocuments.getStatus();
+ InterviewDate interviewDate = internshipToEditDocuments.getInterviewDate();
+ boolean isArchived = internshipToEditDocuments.isArchived();
+
+ ResumeLink resumeLink = editDocumentsDescriptor.getResumeLink()
+ .orElse(internshipToEditDocuments.getDocuments().getResumeLink());
+ CoverLetterLink coverLetterLink = editDocumentsDescriptor.getCoverLetterLink()
+ .orElse(internshipToEditDocuments.getDocuments().getCoverLetterLink());
+
+ Documents newDocuments = new Documents(resumeLink, coverLetterLink);
+
+ return new InternshipApplication(companyName, jobTitle, reviews, programmingLanguages, qualifications, location,
+ salary, notes, rating, reflections, contact, status, isArchived, interviewDate, newDocuments);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof EditDocumentsCommand // instanceof handles nulls
+ && targetIndex.equals(((EditDocumentsCommand) other).targetIndex)
+ && editDocumentsDescriptor.equals((
+ (EditDocumentsCommand) other).editDocumentsDescriptor)); // state check
+ }
+
+ /**
+ * Stores the details to edit the documents with. Each non-empty field value will replace the
+ * corresponding field value of the documents.
+ */
+ public static class EditDocumentsDescriptor {
+ private ResumeLink resumeLink;
+ private CoverLetterLink coverLetterLink;
+
+ public EditDocumentsDescriptor() {}
+
+ /**
+ * Copy constructor.
+ */
+ public EditDocumentsDescriptor(EditDocumentsCommand.EditDocumentsDescriptor toCopy) {
+ setResumeLink(toCopy.resumeLink);
+ setCoverLetterLink(toCopy.coverLetterLink);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(resumeLink, coverLetterLink);
+ }
+
+ public void setResumeLink(ResumeLink resumeLink) {
+ this.resumeLink = resumeLink;
+ }
+
+ public Optional getResumeLink() {
+ return Optional.ofNullable(resumeLink);
+ }
+
+ public void setCoverLetterLink(CoverLetterLink coverLetterLink) {
+ this.coverLetterLink = coverLetterLink;
+ }
+
+ public Optional getCoverLetterLink() {
+ return Optional.ofNullable(coverLetterLink);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditDocumentsCommand.EditDocumentsDescriptor)) {
+ return false;
+ }
+
+ // state check
+ EditDocumentsCommand.EditDocumentsDescriptor e = (EditDocumentsCommand.EditDocumentsDescriptor) other;
+
+ return getResumeLink().equals(e.getResumeLink())
+ && getCoverLetterLink().equals(e.getCoverLetterLink());
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/FindTaskCommand.java b/src/main/java/seedu/address/logic/commands/task/FindTaskCommand.java
new file mode 100644
index 00000000000..72b7a19801d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/FindTaskCommand.java
@@ -0,0 +1,57 @@
+package seedu.address.logic.commands.task;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.model.Model;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.ContentContainsKeywordsPredicate;
+import seedu.address.model.task.TitleContainsKeywordsPredicate;
+
+/**
+ * Finds and lists all todos and notes in record whose name contains any of the argument keywords.
+ * Keyword matching is case-insensitive.
+ */
+public class FindTaskCommand extends Command {
+
+ public static final String COMMAND_WORD = "find_task";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all todos and notes whose company names or "
+ + "contents contain any of the specified keywords (case-insensitive) "
+ + "and displays them as lists with index numbers.\n"
+ + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ + "Example: " + COMMAND_WORD + " google software engineer intern";
+
+ private static final TaskType type = TaskType.BOTH;
+
+ private final TitleContainsKeywordsPredicate titlePredicate;
+ private final ContentContainsKeywordsPredicate contentPredicate;
+
+ /**
+ * Creates a FindTaskCommand instance.
+ * Finds todo and content that match {@code titlePredicate} or {@code contentPredicate}.
+ */
+ public FindTaskCommand(TitleContainsKeywordsPredicate titlePredicate,
+ ContentContainsKeywordsPredicate contentPredicate) {
+ this.titlePredicate = titlePredicate;
+ this.contentPredicate = contentPredicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ assert model != null;
+ model.updateFilteredTodoList(titlePredicate);
+ model.updateFilteredNoteList(contentPredicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_RESULT_LISTED_OVERVIEW,
+ model.getFilteredNoteList().size() + model.getFilteredTodoList().size()), type);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FindTaskCommand // instanceof handles nulls
+ && titlePredicate.equals(((FindTaskCommand) other).titlePredicate)
+ && contentPredicate.equals(((FindTaskCommand) other).contentPredicate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/ListTaskCommand.java b/src/main/java/seedu/address/logic/commands/task/ListTaskCommand.java
new file mode 100644
index 00000000000..a62f5b66a08
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/ListTaskCommand.java
@@ -0,0 +1,45 @@
+package seedu.address.logic.commands.task;
+
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_NOTES;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TODO;
+
+import java.util.List;
+
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.model.Model;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.InternshipTodo;
+import seedu.address.model.task.Note;
+
+/**
+ * Lists all tasks to the user.
+ * The tasks include todo tasks and notes.
+ */
+public class ListTaskCommand extends Command {
+
+ public static final String COMMAND_WORD = "list_task";
+
+ public static final String MESSAGE_SUCCESS = "Listed all todos and notes";
+ public static final String MESSAGE_NO_APPLICATIONS = "No task (todo and note) at the moment";
+
+ private static final TaskType type = TaskType.BOTH;
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ assert model != null;
+
+ model.updateFilteredTodoList(PREDICATE_SHOW_ALL_TODO);
+ model.updateFilteredNoteList(PREDICATE_SHOW_ALL_NOTES);
+
+ List lastShownTodoList = model.getFilteredTodoList();
+ List lastShownNoteList = model.getFilteredNoteList();
+
+ if (lastShownTodoList.size() > 0 || lastShownNoteList.size() > 0) {
+ return new CommandResult(MESSAGE_SUCCESS, type);
+ } else {
+ return new CommandResult(MESSAGE_NO_APPLICATIONS, type);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/note/AddNoteCommand.java b/src/main/java/seedu/address/logic/commands/task/note/AddNoteCommand.java
new file mode 100644
index 00000000000..ebcf7bfc4b9
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/note/AddNoteCommand.java
@@ -0,0 +1,59 @@
+package seedu.address.logic.commands.task.note;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NOTE_CONTENT;
+
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.Note;
+
+/**
+ * Adds a quick note to the note list.
+ */
+public class AddNoteCommand extends Command {
+
+ public static final String COMMAND_WORD = "add_note";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a note.\n"
+ + "Parameters: "
+ + PREFIX_NOTE_CONTENT + "NOTE_CONTENT "
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_NOTE_CONTENT + "Focus on software engineering jobs!";
+
+ public static final String MESSAGE_SUCCESS = "New note added: %1$s";
+ public static final String MESSAGE_DUPLICATE_NOTE = "This note already exists in the todo list";
+
+ private static final TaskType type = TaskType.NOTE;
+
+ private final Note note;
+
+ /**
+ * Creates an AddNoteCommand to add the specified {@code Note}.
+ */
+ public AddNoteCommand(Note noteContent) {
+ requireNonNull(noteContent);
+ note = noteContent;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.hasNote(note)) {
+ throw new CommandException(MESSAGE_DUPLICATE_NOTE);
+ }
+
+ model.addNote(note);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, note), type);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddNoteCommand // instanceof handles nulls
+ && note.equals(((AddNoteCommand) other).note));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/note/ClearNoteCommand.java b/src/main/java/seedu/address/logic/commands/task/note/ClearNoteCommand.java
new file mode 100644
index 00000000000..a4944ecfc8b
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/note/ClearNoteCommand.java
@@ -0,0 +1,39 @@
+package seedu.address.logic.commands.task.note;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.model.Model;
+import seedu.address.model.NoteList;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.Note;
+
+/**
+ * Clears the note list.
+ */
+public class ClearNoteCommand extends Command {
+
+ public static final String COMMAND_WORD = "clear_note";
+ public static final String MESSAGE_SUCCESS = "All notes has been cleared!";
+ public static final String MESSAGE_NULL = "There is nothing to clear!";
+
+ private static final TaskType type = TaskType.NOTE;
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+
+ List lastShownList = model.getFilteredNoteList();
+
+ if (lastShownList.size() == 0) {
+ return new CommandResult(MESSAGE_NULL, type);
+ }
+
+ model.clearNote(new NoteList());
+
+ return new CommandResult(MESSAGE_SUCCESS, type);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/note/DeleteNoteCommand.java b/src/main/java/seedu/address/logic/commands/task/note/DeleteNoteCommand.java
new file mode 100644
index 00000000000..3e8cc653597
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/note/DeleteNoteCommand.java
@@ -0,0 +1,65 @@
+package seedu.address.logic.commands.task.note;
+
+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.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.Note;
+
+/**
+ * Deletes a note identified by its displayed index from the note list.
+ */
+public class DeleteNoteCommand extends Command {
+
+ public static final String COMMAND_WORD = "delete_note";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the specified note from the list of notes.\n"
+ + "Deletes note at the specified INDEX.\n"
+ + "The index refers to the index number shown in the displayed note list.\n"
+ + "Parameters: INDEX (must be a positive integer 1, 2, 3, ...)\n"
+ + "Example: " + COMMAND_WORD + " 2";
+
+ public static final String MESSAGE_DELETE_NOTE_SUCCESS = "Deleted note: %1$s";
+
+ private static final TaskType type = TaskType.NOTE;
+
+ private final Index targetIndex;
+
+ /**
+ * Creates a DeleteNoteCommand to delete the specified note at {@code targetIndex}.
+ */
+ public DeleteNoteCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredNoteList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_NOTE_DISPLAYED_INDEX);
+ }
+
+ Note noteToDelete = lastShownList.get(targetIndex.getZeroBased());
+
+ model.deleteNote(noteToDelete);
+
+ return new CommandResult(String.format(MESSAGE_DELETE_NOTE_SUCCESS, noteToDelete), type);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteNoteCommand // instanceof handles nulls
+ && targetIndex.equals(((DeleteNoteCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/note/ListNoteCommand.java b/src/main/java/seedu/address/logic/commands/task/note/ListNoteCommand.java
new file mode 100644
index 00000000000..5de0445df16
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/note/ListNoteCommand.java
@@ -0,0 +1,39 @@
+package seedu.address.logic.commands.task.note;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_NOTES;
+
+import java.util.List;
+
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.model.Model;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.Note;
+
+/**
+ * Lists all notes in the note list to the user.
+ */
+public class ListNoteCommand extends Command {
+
+ public static final String COMMAND_WORD = "list_note";
+ public static final String MESSAGE_SUCCESS = "Listed all notes";
+ public static final String MESSAGE_NO_NOTE = "No note at the moment";
+
+ private static final TaskType type = TaskType.NOTE;
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+
+ model.updateFilteredNoteList(PREDICATE_SHOW_ALL_NOTES);
+ List lastShownList = model.getFilteredNoteList();
+
+ if (lastShownList.size() > 0) {
+ return new CommandResult(MESSAGE_SUCCESS, type);
+ } else {
+ return new CommandResult(MESSAGE_NO_NOTE, type);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/todo/AddTodoCommand.java b/src/main/java/seedu/address/logic/commands/task/todo/AddTodoCommand.java
new file mode 100644
index 00000000000..8455a3f611b
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/todo/AddTodoCommand.java
@@ -0,0 +1,65 @@
+package seedu.address.logic.commands.task.todo;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DEADLINE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB_TITLE;
+
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.InternshipTodo;
+
+/**
+ * Adds a todo internship application to the todo list.
+ */
+public class AddTodoCommand extends Command {
+
+ public static final String COMMAND_WORD = "add_todo";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds an interested internship todo.\n"
+ + "Parameters: "
+ + PREFIX_COMPANY_NAME + "COMPANY_NAME "
+ + PREFIX_JOB_TITLE + "JOB_TITLE\n"
+ + PREFIX_DEADLINE + "DEADLINE\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_COMPANY_NAME + "LinkedIn "
+ + PREFIX_JOB_TITLE + "Software Engineer "
+ + PREFIX_DEADLINE + "2023-10-01";
+
+ public static final String MESSAGE_SUCCESS = "New TODO added: %1$s";
+ public static final String MESSAGE_DUPLICATE_TODO = "This TODO already exists in the todo list";
+
+ private static final TaskType type = TaskType.TODO;
+
+ private final InternshipTodo todo;
+
+ /**
+ * Creates an AddTodoCommand to add the specified {@code InternshipTodo}
+ */
+ public AddTodoCommand(InternshipTodo applicationTodo) {
+ requireNonNull(applicationTodo);
+ todo = applicationTodo;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.hasTodo(todo)) {
+ throw new CommandException(MESSAGE_DUPLICATE_TODO);
+ }
+
+ model.addTodo(todo);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, todo), type);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddTodoCommand // instanceof handles nulls
+ && todo.equals(((AddTodoCommand) other).todo));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/todo/ClearTodoCommand.java b/src/main/java/seedu/address/logic/commands/task/todo/ClearTodoCommand.java
new file mode 100644
index 00000000000..28128f6b20a
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/todo/ClearTodoCommand.java
@@ -0,0 +1,39 @@
+package seedu.address.logic.commands.task.todo;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.model.Model;
+import seedu.address.model.TodoList;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.InternshipTodo;
+
+/**
+ * Clears the todo list.
+ */
+public class ClearTodoCommand extends Command {
+
+ public static final String COMMAND_WORD = "clear_todo";
+ public static final String MESSAGE_SUCCESS = "All todos have been cleared!";
+ public static final String MESSAGE_NULL = "There is nothing to clear!";
+
+ private static final TaskType type = TaskType.TODO;
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+
+ List lastShownList = model.getFilteredTodoList();
+
+ if (lastShownList.size() == 0) {
+ return new CommandResult(MESSAGE_NULL, type);
+ }
+
+ model.clearTodo(new TodoList());
+
+ return new CommandResult(MESSAGE_SUCCESS, type);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/todo/DeleteTodoCommand.java b/src/main/java/seedu/address/logic/commands/task/todo/DeleteTodoCommand.java
new file mode 100644
index 00000000000..3e3bd948ae9
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/todo/DeleteTodoCommand.java
@@ -0,0 +1,65 @@
+package seedu.address.logic.commands.task.todo;
+
+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.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.InternshipTodo;
+
+/**
+ * Deletes a todo identified by its displayed index from the todo list.
+ */
+public class DeleteTodoCommand extends Command {
+
+ public static final String COMMAND_WORD = "delete_todo";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the specified todo from the list of todo.\n"
+ + "Deletes todo at the specified INDEX.\n"
+ + "The index refers to the index number shown in the displayed todo list.\n"
+ + "Parameters: INDEX (must be a positive integer 1, 2, 3, ...)\n"
+ + "Example: " + COMMAND_WORD + " 2";
+
+ public static final String MESSAGE_DELETE_TODO_SUCCESS = "Deleted todo: %1$s";
+
+ private static final TaskType type = TaskType.TODO;
+
+ private final Index targetIndex;
+
+ /**
+ * Creates a DeleteTodoCommand to delete a todo task at the specified {@code targetIndex}.
+ */
+ public DeleteTodoCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredTodoList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_TODO_DISPLAYED_INDEX);
+ }
+
+ InternshipTodo todoToDelete = lastShownList.get(targetIndex.getZeroBased());
+
+ model.deleteTodo(todoToDelete);
+
+ return new CommandResult(String.format(MESSAGE_DELETE_TODO_SUCCESS, todoToDelete), type);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteTodoCommand // instanceof handles nulls
+ && targetIndex.equals(((DeleteTodoCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/todo/EditDeadlineCommand.java b/src/main/java/seedu/address/logic/commands/task/todo/EditDeadlineCommand.java
new file mode 100644
index 00000000000..1e3ebd5b641
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/todo/EditDeadlineCommand.java
@@ -0,0 +1,100 @@
+package seedu.address.logic.commands.task.todo;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DEADLINE;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TODO;
+
+import java.util.List;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.ApplicationDeadline;
+import seedu.address.model.task.InternshipTodo;
+import seedu.address.model.task.NoteContent;
+
+/**
+ * Edits the deadline of a todo identified by its displayed index from the list of todos.
+ */
+public class EditDeadlineCommand extends Command {
+
+ public static final String COMMAND_WORD = "edit_deadline";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Edits the deadline of the specified todo from current available todo list.\n"
+ + "Parameters: INDEX (INDEX must be a positive integer) "
+ + PREFIX_DEADLINE + "DEADLINE (must be in format yyyy-mm-dd)\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_DEADLINE + "2023-10-01\n";
+
+ public static final String MESSAGE_UPDATE_STATUS_SUCCESS = "Deadline updated: %1$s";
+
+ private static final TaskType type = TaskType.TODO;
+
+ private final Index targetIndex;
+
+ private final ApplicationDeadline toUpdate;
+
+ /**
+ * Creates a EditDeadlineCommand to update the deadline of the todo task specified at index {@code targetIndex} to
+ * {@code deadline}.
+ */
+ public EditDeadlineCommand(Index targetIndex, ApplicationDeadline deadline) {
+ requireNonNull(targetIndex);
+ requireNonNull(deadline);
+
+ this.targetIndex = targetIndex;
+ toUpdate = deadline;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ List lastShownList = model.getFilteredTodoList();
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_DISPLAYED_INDEX);
+ }
+
+ InternshipTodo todoToUpdateDeadline = lastShownList.get(
+ targetIndex.getZeroBased());
+ InternshipTodo updatedTodo = createdUpdatedTodo(
+ todoToUpdateDeadline, toUpdate);
+
+ model.setTodo(todoToUpdateDeadline, updatedTodo);
+ model.updateFilteredTodoList(PREDICATE_SHOW_ALL_TODO);
+ return new CommandResult(String.format(MESSAGE_UPDATE_STATUS_SUCCESS, updatedTodo), type);
+ }
+
+ /**
+ * Creates and returns a {@code InternshipTodo} with the deadline of {@code deadline}
+ */
+ private static InternshipTodo createdUpdatedTodo(
+ InternshipTodo todo, ApplicationDeadline deadline) {
+ assert todo != null;
+
+ CompanyName companyName = todo.getInternshipTitle();
+ JobTitle jobTitle = todo.getJobTitle();
+ NoteContent note = todo.getNote();
+
+ if (note != null) {
+ return new InternshipTodo(companyName, jobTitle, deadline, note);
+ } else {
+ return new InternshipTodo(companyName, jobTitle, deadline);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof EditDeadlineCommand // instanceof handles nulls
+ && targetIndex.equals(((EditDeadlineCommand) other).targetIndex)
+ && toUpdate.equals(((EditDeadlineCommand) other).toUpdate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/todo/EditNoteContentCommand.java b/src/main/java/seedu/address/logic/commands/task/todo/EditNoteContentCommand.java
new file mode 100644
index 00000000000..83314d04a05
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/todo/EditNoteContentCommand.java
@@ -0,0 +1,95 @@
+package seedu.address.logic.commands.task.todo;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NOTE_CONTENT;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TODO;
+
+import java.util.List;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.ApplicationDeadline;
+import seedu.address.model.task.InternshipTodo;
+import seedu.address.model.task.NoteContent;
+
+/**
+ * Edits the note content of a todo identified by its displayed index from the list of todos.
+ */
+public class EditNoteContentCommand extends Command {
+
+ public static final String COMMAND_WORD = "edit_content";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Edits the note content of the specified todo from current available todo list.\n"
+ + "Parameters: INDEX (INDEX must be a positive integer) "
+ + PREFIX_NOTE_CONTENT + "NOTE_CONTENT\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_NOTE_CONTENT + "Change venue\n";
+
+ public static final String MESSAGE_UPDATE_STATUS_SUCCESS = "NoteList Content updated: %1$s";
+
+ private static final TaskType type = TaskType.TODO;
+
+ private final Index targetIndex;
+
+ private final NoteContent toUpdate;
+
+ /**
+ * Creates a EditNoteContentCommand to update the note content of the todo task specified at index
+ * {@code targetIndex} to {@code content}.
+ */
+ public EditNoteContentCommand(Index targetIndex, NoteContent content) {
+ requireNonNull(targetIndex);
+ requireNonNull(content);
+
+ this.targetIndex = targetIndex;
+ toUpdate = content;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ List lastShownList = model.getFilteredTodoList();
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_DISPLAYED_INDEX);
+ }
+
+ InternshipTodo todoToUpdateNote = lastShownList.get(
+ targetIndex.getZeroBased());
+ InternshipTodo updatedTodo = createdUpdatedTodo(
+ todoToUpdateNote, toUpdate);
+
+ model.setTodo(todoToUpdateNote, updatedTodo);
+ model.updateFilteredTodoList(PREDICATE_SHOW_ALL_TODO);
+ return new CommandResult(String.format(MESSAGE_UPDATE_STATUS_SUCCESS, updatedTodo), type);
+ }
+
+ /**
+ * Creates and returns a {@code InternshipTodo} with the content of {@code content}
+ */
+ private static InternshipTodo createdUpdatedTodo(InternshipTodo todo, NoteContent content) {
+ assert todo != null;
+
+ CompanyName companyName = todo.getInternshipTitle();
+ JobTitle jobTitle = todo.getJobTitle();
+ ApplicationDeadline deadline = todo.getDeadline();
+
+ return new InternshipTodo(companyName, jobTitle, deadline, content);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof EditNoteContentCommand // instanceof handles nulls
+ && targetIndex.equals(((EditNoteContentCommand) other).targetIndex)
+ && toUpdate.equals(((EditNoteContentCommand) other).toUpdate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/task/todo/ListTodoCommand.java b/src/main/java/seedu/address/logic/commands/task/todo/ListTodoCommand.java
new file mode 100644
index 00000000000..409cf95e670
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/task/todo/ListTodoCommand.java
@@ -0,0 +1,36 @@
+package seedu.address.logic.commands.task.todo;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TODO;
+
+import java.util.List;
+
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.model.Model;
+import seedu.address.model.tag.TaskType;
+import seedu.address.model.task.InternshipTodo;
+/**
+ * Lists all todo applications in the todo list to the user.
+ */
+public class ListTodoCommand extends Command {
+
+ public static final String COMMAND_WORD = "list_todo";
+ public static final String MESSAGE_SUCCESS = "Listed all todos";
+ public static final String MESSAGE_NO_APPLICATIONS = "No todo at the moment";
+
+ private static final TaskType type = TaskType.TODO;
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredTodoList(PREDICATE_SHOW_ALL_TODO);
+ List lastShownList = model.getFilteredTodoList();
+ if (lastShownList.size() > 0) {
+ return new CommandResult(MESSAGE_SUCCESS, type);
+ } else {
+ return new CommandResult(MESSAGE_NO_APPLICATIONS, type);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
index 3b8bfa035e8..aeed1f8c5f8 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
@@ -1,23 +1,33 @@
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 static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB_TITLE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LOCATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NOTE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_QUALIFICATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_RATING;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REFLECTION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REVIEW;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
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;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipApplication;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
/**
* Parses input arguments and creates a new AddCommand object
@@ -31,22 +41,33 @@ public class AddCommandParser implements Parser {
*/
public AddCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(args, PREFIX_COMPANY_NAME, PREFIX_JOB_TITLE, PREFIX_REVIEW, PREFIX_LOCATION,
+ PREFIX_PROGRAMMING_LANGUAGE, PREFIX_QUALIFICATION, PREFIX_SALARY, PREFIX_RATING, PREFIX_NOTE,
+ PREFIX_REFLECTION);
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
+ if (!arePrefixesPresent(argMultimap, PREFIX_COMPANY_NAME, PREFIX_JOB_TITLE)
|| !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));
+ CompanyName companyName = ParserUtil.parseCompanyName(
+ argMultimap.getValue(PREFIX_COMPANY_NAME).orElse(null));
+ JobTitle jobTitle = ParserUtil.parseJobTitle(argMultimap.getValue(PREFIX_JOB_TITLE).orElse(null));
+ Set reviewList = ParserUtil.parseReviews(argMultimap.getAllValues(PREFIX_REVIEW));
+ Set programmingLanguages = ParserUtil.parseProgrammingLanguages(
+ argMultimap.getAllValues(PREFIX_PROGRAMMING_LANGUAGE));
+ Set qualifications = ParserUtil.parseQualifications(
+ argMultimap.getAllValues(PREFIX_QUALIFICATION));
+ Location location = ParserUtil.parseLocation(argMultimap.getValue(PREFIX_LOCATION).orElse(null));
+ Salary salary = ParserUtil.parseSalary(argMultimap.getValue(PREFIX_SALARY).orElse(null));
+ Set notes = ParserUtil.parseNotes(argMultimap.getAllValues(PREFIX_NOTE));
+ Rating rating = ParserUtil.parseRating(argMultimap.getValue(PREFIX_RATING).orElse(null));
+ Set reflections = ParserUtil.parseReflections(argMultimap.getAllValues(PREFIX_REFLECTION));
- Person person = new Person(name, phone, email, address, tagList);
+ InternshipApplication application = new InternshipApplication(companyName, jobTitle, reviewList,
+ programmingLanguages, qualifications, location, salary, notes, rating, reflections);
- return new AddCommand(person);
+ return new AddCommand(application);
}
/**
diff --git a/src/main/java/seedu/address/logic/parser/AddInterviewDateCommandParser.java b/src/main/java/seedu/address/logic/parser/AddInterviewDateCommandParser.java
new file mode 100644
index 00000000000..bbde1460efb
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddInterviewDateCommandParser.java
@@ -0,0 +1,53 @@
+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_DATE;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.AddInterviewDateCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.application.InterviewDate;
+
+/**
+ * Parses input arguments and creates a new AddInterviewDateCommand object
+ */
+public class AddInterviewDateCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddInterviewDateCommand
+ * and returns an AddInterviewDateCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddInterviewDateCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_DATE);
+
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException e) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ AddInterviewDateCommand.MESSAGE_USAGE));
+ }
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_DATE)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ AddInterviewDateCommand.MESSAGE_USAGE));
+ }
+
+ InterviewDate interviewDate = ParserUtil.parseInterviewDate(argMultimap.getValue(PREFIX_DATE).get());
+
+ return new AddInterviewDateCommand(index, interviewDate);
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
deleted file mode 100644
index 1e466792b46..00000000000
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.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;
-
-/**
- * Parses user input.
- */
-public class AddressBookParser {
-
- /**
- * Used for initial separation of command word and args.
- */
- private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)");
-
- /**
- * Parses user input into command for execution.
- *
- * @param userInput full user input string
- * @return the command based on the user input
- * @throws ParseException if the user input does not conform the expected format
- */
- public Command parseCommand(String userInput) throws ParseException {
- final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
- if (!matcher.matches()) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
- }
-
- final String commandWord = matcher.group("commandWord");
- final String arguments = matcher.group("arguments");
- switch (commandWord) {
-
- case AddCommand.COMMAND_WORD:
- return new AddCommandParser().parse(arguments);
-
- case EditCommand.COMMAND_WORD:
- return new EditCommandParser().parse(arguments);
-
- case DeleteCommand.COMMAND_WORD:
- return new DeleteCommandParser().parse(arguments);
-
- case ClearCommand.COMMAND_WORD:
- return new ClearCommand();
-
- case FindCommand.COMMAND_WORD:
- return new FindCommandParser().parse(arguments);
-
- case ListCommand.COMMAND_WORD:
- return new ListCommand();
-
- case ExitCommand.COMMAND_WORD:
- return new ExitCommand();
-
- case HelpCommand.COMMAND_WORD:
- return new HelpCommand();
-
- default:
- throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/ArchiveCommandParser.java b/src/main/java/seedu/address/logic/parser/ArchiveCommandParser.java
new file mode 100644
index 00000000000..a0500cfaf16
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ArchiveCommandParser.java
@@ -0,0 +1,28 @@
+package seedu.address.logic.parser;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.ArchiveCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new ArchiveCommand object
+ */
+public class ArchiveCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ArchiveCommand
+ * and returns a ArchiveCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ArchiveCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new ArchiveCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, ArchiveCommand.MESSAGE_USAGE), pe);
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/ClearByCommandParser.java b/src/main/java/seedu/address/logic/parser/ClearByCommandParser.java
new file mode 100644
index 00000000000..253e1dff0e2
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ClearByCommandParser.java
@@ -0,0 +1,83 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB_TITLE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_STATUS;
+
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.ClearByCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.JobTitle;
+
+/**
+ * Parses input arguments and creates a new ClearByCommand object
+ */
+public class ClearByCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ClearByCommand
+ * and returns an ClearByCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ClearByCommand parse(String args) throws ParseException {
+ Prefix prefix;
+
+ try {
+ String trimArgs = args.trim();
+ prefix = new Prefix(trimArgs.substring(0, 2));
+ } catch (IndexOutOfBoundsException ite) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ ClearByCommand.MESSAGE_NO_PARAMETER));
+ }
+
+ if (!(prefix.equals(PREFIX_COMPANY_NAME) || prefix.equals(PREFIX_JOB_TITLE) || prefix.equals(PREFIX_STATUS))) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ ClearByCommand.MESSAGE_INVALID_PARAMETER));
+ }
+
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, prefix);
+
+ if (!arePrefixesPresent(argMultimap, prefix)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ClearByCommand.MESSAGE_USAGE));
+ }
+
+ return parseParameter(prefix, argMultimap);
+ }
+
+ private ClearByCommand parseParameter(Prefix prefix, ArgumentMultimap argMultimap) throws ParseException {
+ if (prefix.equals(PREFIX_COMPANY_NAME)) {
+ CompanyName companyName = ParserUtil.parseCompanyName(
+ argMultimap.getValue(PREFIX_COMPANY_NAME).orElse(null));
+
+ return new ClearByCommand(companyName);
+ } else if (prefix.equals(PREFIX_JOB_TITLE)) {
+ JobTitle jobTitle = ParserUtil.parseJobTitle(argMultimap.getValue(PREFIX_JOB_TITLE).orElse(null));
+
+ return new ClearByCommand(jobTitle);
+ } else if (prefix.equals(PREFIX_STATUS)) {
+ InternshipStatus status = ParserUtil.parseInternshipStatus(
+ argMultimap.getValue(PREFIX_STATUS).orElse(null));
+
+ return new ClearByCommand(status);
+ } else {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ ClearByCommand.MESSAGE_INVALID_PARAMETER));
+ }
+ }
+
+ /**
+ * 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
index 75b1a9bf119..46cbd1bb217 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java
@@ -6,10 +6,33 @@
public class CliSyntax {
/* Prefix definitions */
- public static final Prefix PREFIX_NAME = new Prefix("n/");
+ /* Prefix used in AddCommand */
+ public static final Prefix PREFIX_COMPANY_NAME = new Prefix("n/");
+ public static final Prefix PREFIX_JOB_TITLE = new Prefix("j/");
+ public static final Prefix PREFIX_REVIEW = new Prefix("r/");
+ public static final Prefix PREFIX_PROGRAMMING_LANGUAGE = new Prefix("p/");
+ public static final Prefix PREFIX_QUALIFICATION = new Prefix("q/");
+ public static final Prefix PREFIX_LOCATION = new Prefix("l/");
+ public static final Prefix PREFIX_SALARY = new Prefix("s/");
+ public static final Prefix PREFIX_NOTE = new Prefix("note/");
+ public static final Prefix PREFIX_RATING = new Prefix("rate/");
+ public static final Prefix PREFIX_REFLECTION = new Prefix("reflect/");
+
+ /* Prefix used in AddContactCommand */
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/");
+ public static final Prefix PREFIX_STATUS = new Prefix("s/");
+ public static final Prefix PREFIX_DEADLINE = new Prefix("by/");
+ public static final Prefix PREFIX_NOTE_CONTENT = new Prefix("c/");
+ public static final Prefix PREFIX_DATE = new Prefix("d/");
+ public static final Prefix PREFIX_RESUME = new Prefix("rs/");
+ public static final Prefix PREFIX_COVER_LETTER = new Prefix("cl/");
+
+ /* Prefix used in FindDateCommand */
+ public static final Prefix PREFIX_DATE_BEFORE = new Prefix("before/");
+ public static final Prefix PREFIX_DATE_AFTER = new Prefix("after/");
+ public static final Prefix PREFIX_DATE_FROM = new Prefix("from/");
+ public static final Prefix PREFIX_DATE_TO = new Prefix("to/");
+
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
index 522b93081cc..72e965196fa 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
@@ -14,6 +14,7 @@ public class DeleteCommandParser implements Parser {
/**
* Parses the given {@code String} of arguments in the context of the DeleteCommand
* and returns a DeleteCommand object for execution.
+ *
* @throws ParseException if the user input does not conform the expected format
*/
public DeleteCommand parse(String args) throws ParseException {
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
index 845644b7dea..1d185e8ec2e 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
@@ -2,11 +2,16 @@
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 static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB_TITLE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_LOCATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NOTE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_QUALIFICATION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_RATING;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REFLECTION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REVIEW;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
import java.util.Collection;
import java.util.Collections;
@@ -15,9 +20,13 @@
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
+import seedu.address.logic.commands.EditCommand.EditInternshipDescriptor;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
/**
* Parses input arguments and creates a new EditCommand object
@@ -32,7 +41,9 @@ public class EditCommandParser implements Parser {
public EditCommand parse(String args) throws ParseException {
requireNonNull(args);
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(args, PREFIX_COMPANY_NAME, PREFIX_JOB_TITLE, PREFIX_LOCATION, PREFIX_SALARY,
+ PREFIX_RATING, PREFIX_QUALIFICATION, PREFIX_PROGRAMMING_LANGUAGE, PREFIX_REVIEW, PREFIX_NOTE,
+ PREFIX_REFLECTION);
Index index;
@@ -42,41 +53,124 @@ public EditCommand parse(String args) throws ParseException {
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()));
+ EditInternshipDescriptor editInternshipDescriptor = new EditInternshipDescriptor();
+ if (argMultimap.getValue(PREFIX_COMPANY_NAME).isPresent()) {
+ editInternshipDescriptor.setCompanyName(ParserUtil
+ .parseCompanyName(argMultimap.getValue(PREFIX_COMPANY_NAME).get()));
}
- if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
- editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
+ if (argMultimap.getValue(PREFIX_JOB_TITLE).isPresent()) {
+ editInternshipDescriptor.setJobTitle(ParserUtil
+ .parseJobTitle(argMultimap.getValue(PREFIX_JOB_TITLE).get()));
}
- if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
+ if (argMultimap.getValue(PREFIX_LOCATION).isPresent()) {
+ editInternshipDescriptor.setLocation(ParserUtil
+ .parseLocation(argMultimap.getValue(PREFIX_LOCATION).get()));
}
- if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
- editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
+ if (argMultimap.getValue(PREFIX_SALARY).isPresent()) {
+ editInternshipDescriptor.setSalary(ParserUtil.parseSalary(argMultimap.getValue(PREFIX_SALARY).get()));
}
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
+ if (argMultimap.getValue(PREFIX_RATING).isPresent()) {
+ editInternshipDescriptor.setRating(ParserUtil.parseRating(argMultimap.getValue(PREFIX_RATING).get()));
+ }
+ parseQualificationsForEdit(argMultimap.getAllValues(PREFIX_QUALIFICATION))
+ .ifPresent(editInternshipDescriptor::setQualifications);
+ parseProgrammingLanguageForEdit(argMultimap.getAllValues(PREFIX_PROGRAMMING_LANGUAGE))
+ .ifPresent(editInternshipDescriptor::setProgrammingLanguages);
+ parseReviewsForEdit(argMultimap.getAllValues(PREFIX_REVIEW)).ifPresent(editInternshipDescriptor::setReviews);
+ parseNotesForEdit(argMultimap.getAllValues(PREFIX_NOTE)).ifPresent(editInternshipDescriptor::setNotes);
+ parseReflectionsForEdit(argMultimap.getAllValues(PREFIX_REFLECTION))
+ .ifPresent(editInternshipDescriptor::setReflections);
- if (!editPersonDescriptor.isAnyFieldEdited()) {
+ if (!editInternshipDescriptor.isAnyFieldEdited()) {
throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
}
- return new EditCommand(index, editPersonDescriptor);
+ return new EditCommand(index, editInternshipDescriptor);
+ }
+
+ /**
+ * Parses {@code Collection qualifications} into a {@code Set} if {@code qualifications}
+ * is non-empty. If {@code qualifications} contain only one element which is an empty string, it will be parsed into
+ * a {@code Set} containing zero qualifications.
+ */
+ private Optional> parseQualificationsForEdit(Collection qualifications)
+ throws ParseException {
+ assert qualifications != null;
+
+ if (qualifications.isEmpty()) {
+ return Optional.empty();
+ }
+ Collection qualificationSet = qualifications.size() == 1 && qualifications.contains("")
+ ? Collections.emptySet() : qualifications;
+ return Optional.of(ParserUtil.parseQualifications(qualificationSet));
+ }
+
+ /**
+ * Parses {@code Collection programmingLanguages} into a {@code Set} if
+ * {@code programmingLanguages} is non-empty. If {@code programmingLanguages} contain only one element which is an
+ * empty string, it will be parsed into a {@code Set} containing zero programmingLanguages.
+ */
+ private Optional> parseProgrammingLanguageForEdit(Collection programmingLanguages)
+ throws ParseException {
+ assert programmingLanguages != null;
+
+ if (programmingLanguages.isEmpty()) {
+ return Optional.empty();
+ }
+ Collection programmingLanguageSet = programmingLanguages.size() == 1 && programmingLanguages
+ .contains("") ? Collections.emptySet() : programmingLanguages;
+ return Optional.of(ParserUtil.parseProgrammingLanguages(programmingLanguageSet));
+ }
+
+ /**
+ * Parses {@code Collection reviews} into a {@code Set} if {@code reviews}
+ * is non-empty. If {@code reviews} contain only one element which is an empty string, it will be parsed into
+ * a {@code Set} containing zero reviews.
+ */
+ private Optional> parseReviewsForEdit(Collection reviews)
+ throws ParseException {
+ assert reviews != null;
+
+ if (reviews.isEmpty()) {
+ return Optional.empty();
+ }
+ Collection reviewSet = reviews.size() == 1 && reviews.contains("")
+ ? Collections.emptySet() : reviews;
+ return Optional.of(ParserUtil.parseReviews(reviewSet));
+ }
+
+ /**
+ * Parses {@code Collection notes} into a {@code Set} if {@code notes}
+ * is non-empty. If {@code notes} contain only one element which is an empty string, it will be parsed into
+ * a {@code Set} containing zero notes.
+ */
+ private Optional> parseNotesForEdit(Collection notes)
+ throws ParseException {
+ assert notes != null;
+
+ if (notes.isEmpty()) {
+ return Optional.empty();
+ }
+ Collection noteSet = notes.size() == 1 && notes.contains("")
+ ? Collections.emptySet() : notes;
+ return Optional.of(ParserUtil.parseNotes(noteSet));
}
/**
- * 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.
+ * Parses {@code Collection reflections} into a {@code Set} if {@code reflections}
+ * is non-empty. If {@code reflections} contain only one element which is an empty string, it will be parsed into
+ * a {@code Set} containing zero reflections.
*/
- private Optional> parseTagsForEdit(Collection tags) throws ParseException {
- assert tags != null;
+ private Optional> parseReflectionsForEdit(Collection reflections)
+ throws ParseException {
+ assert reflections != null;
- if (tags.isEmpty()) {
+ if (reflections.isEmpty()) {
return Optional.empty();
}
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
+ Collection reflectionSet = reflections.size() == 1 && reflections.contains("")
+ ? Collections.emptySet() : reflections;
+ return Optional.of(ParserUtil.parseReflections(reflectionSet));
}
}
diff --git a/src/main/java/seedu/address/logic/parser/EditStatusCommandParser.java b/src/main/java/seedu/address/logic/parser/EditStatusCommandParser.java
new file mode 100644
index 00000000000..28e5c021a5d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/EditStatusCommandParser.java
@@ -0,0 +1,55 @@
+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_STATUS;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.EditStatusCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.application.InternshipStatus;
+
+/**
+ * Parses input arguments and creates a new EditStatusCommand object
+ */
+public class EditStatusCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditStatusCommand
+ * and returns an EditStatusCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public EditStatusCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_STATUS);
+
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditStatusCommand.MESSAGE_USAGE),
+ pe);
+ }
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_STATUS)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditStatusCommand.MESSAGE_USAGE));
+ }
+
+ InternshipStatus status = ParserUtil.parseInternshipStatus(argMultimap.getValue(PREFIX_STATUS).get());
+
+ return new EditStatusCommand(index, status);
+ }
+
+ /**
+ * 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/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
index 4fb71f23103..a7bd23a89c0 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
@@ -1,18 +1,142 @@
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_DATE_AFTER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_BEFORE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_FROM;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_TO;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_STATUS;
+import static seedu.address.logic.parser.ParserUtil.MESSAGE_INVALID_INTERVAL;
import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import seedu.address.commons.core.LogsCenter;
import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.FindDateCommand;
+import seedu.address.logic.commands.FindStatusCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.application.AfterDatePredicate;
+import seedu.address.model.application.BeforeDatePredicate;
+import seedu.address.model.application.BetweenDatePredicate;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.NameContainsKeywordsPredicate;
+import seedu.address.model.application.StatusPredicate;
/**
* Parses input arguments and creates a new FindCommand object
*/
public class FindCommandParser implements Parser {
+ /**
+ * Checks if argMultimap contains valid FindCommand options.
+ *
+ * @param argMultimap Maps containing mapping of prefixes to their respective arguments
+ * @return true if and only if the map does not contain any other prefix
+ */
+ private boolean isFindKeywordsCommand(ArgumentMultimap argMultimap) {
+ return !argMultimap.getValue(PREFIX_STATUS).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_BEFORE).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_AFTER).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_FROM).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_TO).isPresent();
+ }
+
+ /**
+ * Checks if argMultimap contains valid FindCommand options
+ *
+ * @param argMultimap Maps containing mapping of prefixes to their respective arguments
+ * @return true if and only if the map contains only prefix {@code PREFIX_STATUS} to its argument
+ */
+ private boolean isFindStatusCommand(ArgumentMultimap argMultimap) {
+ return argMultimap.getValue(PREFIX_STATUS).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_BEFORE).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_AFTER).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_FROM).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_TO).isPresent();
+ }
+
+ /**
+ * Checks if argMultimap contains valid FindCommand options
+ *
+ * @param argMultimap Maps containing mapping of prefixes to their respective arguments
+ * @return true if and only if the map contains only prefix {@code PREFIX_DATE_BEFORE} to its argument
+ */
+ private boolean isFindBeforeDateCommand(ArgumentMultimap argMultimap) {
+ return !argMultimap.getValue(PREFIX_STATUS).isPresent()
+ && argMultimap.getValue(PREFIX_DATE_BEFORE).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_AFTER).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_FROM).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_TO).isPresent();
+ }
+
+ /**
+ * Checks if argMultimap contains valid FindCommand options
+ *
+ * @param argMultimap Maps containing mapping of prefixes to their respective arguments
+ * @return true if and only if the map contains only prefix {@code PREFIX_DATE_AFTER} to its argument
+ */
+ private boolean isFindAfterDateCommand(ArgumentMultimap argMultimap) {
+ return !argMultimap.getValue(PREFIX_STATUS).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_BEFORE).isPresent()
+ && argMultimap.getValue(PREFIX_DATE_AFTER).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_FROM).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_TO).isPresent();
+ }
+
+ /**
+ * Checks if argMultimap contains valid FindCommand options
+ *
+ * @param argMultimap Maps containing mapping of prefixes to their respective arguments
+ * @return true if and only if the map contains only prefixes {@code PREFIX_DATE_FROM}
+ * and {@code PREFIX_DATE_TO} to its argument
+ */
+ private boolean isFindBetweenDateCommand(ArgumentMultimap argMultimap) {
+ return !argMultimap.getValue(PREFIX_STATUS).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_BEFORE).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE_AFTER).isPresent()
+ && argMultimap.getValue(PREFIX_DATE_FROM).isPresent()
+ && argMultimap.getValue(PREFIX_DATE_TO).isPresent();
+ }
+
+ /**
+ * Checks if argMultimap contains valid FindCommand options.
+ *
+ * @param argMultimap Maps containing mapping of prefixes to their respective arguments
+ * @return true if and only if the map contains valid combination of options
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ private boolean verifyFindCommandOptions(ArgumentMultimap argMultimap) throws ParseException {
+ if (!(isFindKeywordsCommand(argMultimap)
+ || isFindStatusCommand(argMultimap)
+ || isFindBeforeDateCommand(argMultimap)
+ || isFindAfterDateCommand(argMultimap)
+ || isFindBetweenDateCommand(argMultimap))) {
+ Logger logger = LogsCenter.getLogger(FindCommandParser.class);
+ logger.log(Level.INFO, "User used an invalid combination of prefixes");
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the given two dates forms valid interval.
+ *
+ * @param startDate The start date of the interval
+ * @param endDate The end date of the interval
+ * @return true if the two dates form a valid interval
+ * @throws ParseException if two dates doesn't form a valid interval
+ */
+ private boolean checkValidInterval(InterviewDate startDate, InterviewDate endDate) throws ParseException {
+ if (!(startDate.isBeforeInclusive(endDate))) {
+ throw new ParseException(MESSAGE_INVALID_INTERVAL);
+ }
+ return true;
+ }
+
/**
* Parses the given {@code String} of arguments in the context of the FindCommand
* and returns a FindCommand object for execution.
@@ -24,9 +148,30 @@ public FindCommand parse(String args) throws ParseException {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
}
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args,
+ PREFIX_STATUS, PREFIX_DATE_BEFORE, PREFIX_DATE_AFTER, PREFIX_DATE_FROM, PREFIX_DATE_TO);
+ verifyFindCommandOptions(argMultimap);
+ if (isFindStatusCommand(argMultimap)) {
+ InternshipStatus status = ParserUtil.parseInternshipStatus(argMultimap.getValue(PREFIX_STATUS).get());
+ return new FindStatusCommand(new StatusPredicate(status));
+ }
+ if (isFindBeforeDateCommand(argMultimap)) {
+ InterviewDate date = ParserUtil.parseInterviewDate(argMultimap.getValue(PREFIX_DATE_BEFORE).get());
+ return new FindDateCommand(new BeforeDatePredicate(date));
+ }
+ if (isFindAfterDateCommand(argMultimap)) {
+ InterviewDate date = ParserUtil.parseInterviewDate(argMultimap.getValue(PREFIX_DATE_AFTER).get());
+ return new FindDateCommand(new AfterDatePredicate(date));
+ }
+ if (isFindBetweenDateCommand(argMultimap)) {
+ InterviewDate startDate = ParserUtil.parseInterviewDate(argMultimap.getValue(PREFIX_DATE_FROM).get());
+ InterviewDate endDate = ParserUtil.parseInterviewDate(argMultimap.getValue(PREFIX_DATE_TO).get());
+ checkValidInterval(startDate, endDate);
+ return new FindDateCommand(new BetweenDatePredicate(startDate, endDate));
+ }
String[] nameKeywords = trimmedArgs.split("\\s+");
-
return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
}
diff --git a/src/main/java/seedu/address/logic/parser/InternEaseParser.java b/src/main/java/seedu/address/logic/parser/InternEaseParser.java
new file mode 100644
index 00000000000..6cccf19c260
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/InternEaseParser.java
@@ -0,0 +1,172 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.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.AddInterviewDateCommand;
+import seedu.address.logic.commands.ArchiveCommand;
+import seedu.address.logic.commands.ClearByCommand;
+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.EditStatusCommand;
+import seedu.address.logic.commands.ExitCommand;
+import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.HelpCommand;
+import seedu.address.logic.commands.ListArchivedCommand;
+import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.RemindCommand;
+import seedu.address.logic.commands.RevertAllCommand;
+import seedu.address.logic.commands.RevertCommand;
+import seedu.address.logic.commands.SortCommand;
+import seedu.address.logic.commands.UnarchiveCommand;
+import seedu.address.logic.commands.contact.AddContactCommand;
+import seedu.address.logic.commands.contact.DeleteContactCommand;
+import seedu.address.logic.commands.contact.EditContactCommand;
+import seedu.address.logic.commands.documents.AddDocumentsCommand;
+import seedu.address.logic.commands.documents.DeleteDocumentsCommand;
+import seedu.address.logic.commands.documents.EditDocumentsCommand;
+import seedu.address.logic.commands.task.FindTaskCommand;
+import seedu.address.logic.commands.task.ListTaskCommand;
+import seedu.address.logic.commands.task.note.AddNoteCommand;
+import seedu.address.logic.commands.task.note.ClearNoteCommand;
+import seedu.address.logic.commands.task.note.DeleteNoteCommand;
+import seedu.address.logic.commands.task.note.ListNoteCommand;
+import seedu.address.logic.commands.task.todo.AddTodoCommand;
+import seedu.address.logic.commands.task.todo.ClearTodoCommand;
+import seedu.address.logic.commands.task.todo.DeleteTodoCommand;
+import seedu.address.logic.commands.task.todo.EditDeadlineCommand;
+import seedu.address.logic.commands.task.todo.EditNoteContentCommand;
+import seedu.address.logic.commands.task.todo.ListTodoCommand;
+import seedu.address.logic.parser.contact.ContactParser;
+import seedu.address.logic.parser.documents.DocumentsParser;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.logic.parser.task.TaskParser;
+
+/**
+ * Parses user input.
+ */
+public class InternEaseParser {
+
+ /**
+ * Used for initial separation of command word and args.
+ */
+ private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)");
+ private final TaskParser taskParser;
+ private final DocumentsParser documentsParser;
+ private final ContactParser contactParser;
+
+ /**
+ * Creates a TaskParser instance for every InternEase parser object.
+ */
+ public InternEaseParser() {
+ taskParser = new TaskParser();
+ documentsParser = new DocumentsParser();
+ contactParser = new ContactParser();
+ }
+
+ /**
+ * Parses user input into command for execution.
+ *
+ * @param userInput full user input string
+ * @return the command based on the user input
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public Command parseCommand(String userInput) throws ParseException {
+ final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
+ if (!matcher.matches()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
+ }
+
+ final String commandWord = matcher.group("commandWord");
+ final String arguments = matcher.group("arguments");
+ switch (commandWord) {
+
+ case AddCommand.COMMAND_WORD:
+ return new AddCommandParser().parse(arguments);
+
+ case EditCommand.COMMAND_WORD:
+ return new EditCommandParser().parse(arguments);
+
+ case DeleteCommand.COMMAND_WORD:
+ return new DeleteCommandParser().parse(arguments);
+
+ case ClearCommand.COMMAND_WORD:
+ return new ClearCommand();
+
+ case FindCommand.COMMAND_WORD:
+ return new FindCommandParser().parse(arguments);
+
+ case SortCommand.COMMAND_WORD:
+ return new SortCommandParser().parse(arguments);
+
+ case ListCommand.COMMAND_WORD:
+ return new ListCommand();
+
+ case ExitCommand.COMMAND_WORD:
+ return new ExitCommand();
+
+ case HelpCommand.COMMAND_WORD:
+ return new HelpCommand();
+
+ case RemindCommand.COMMAND_WORD:
+ return new RemindCommand();
+
+ case EditStatusCommand.COMMAND_WORD:
+ return new EditStatusCommandParser().parse(arguments);
+
+ case AddContactCommand.COMMAND_WORD:
+ case EditContactCommand.COMMAND_WORD:
+ case DeleteContactCommand.COMMAND_WORD:
+ return contactParser.parseContactCommand(commandWord, arguments);
+
+ case ClearByCommand.COMMAND_WORD:
+ return new ClearByCommandParser().parse(arguments);
+
+ case ArchiveCommand.COMMAND_WORD:
+ return new ArchiveCommandParser().parse(arguments);
+
+ case UnarchiveCommand.COMMAND_WORD:
+ return new UnarchiveCommandParser().parse(arguments);
+
+ case ListArchivedCommand.COMMAND_WORD:
+ return new ListArchivedCommand();
+
+ case AddInterviewDateCommand.COMMAND_WORD:
+ return new AddInterviewDateCommandParser().parse(arguments);
+
+ case RevertCommand.COMMAND_WORD:
+ return new RevertCommand();
+
+ case RevertAllCommand.COMMAND_WORD:
+ return new RevertAllCommand();
+
+ case ListTaskCommand.COMMAND_WORD:
+ case FindTaskCommand.COMMAND_WORD:
+ case AddTodoCommand.COMMAND_WORD:
+ case ListTodoCommand.COMMAND_WORD:
+ case EditDeadlineCommand.COMMAND_WORD:
+ case EditNoteContentCommand.COMMAND_WORD:
+ case DeleteTodoCommand.COMMAND_WORD:
+ case ClearTodoCommand.COMMAND_WORD:
+ case AddNoteCommand.COMMAND_WORD:
+ case ListNoteCommand.COMMAND_WORD:
+ case DeleteNoteCommand.COMMAND_WORD:
+ case ClearNoteCommand.COMMAND_WORD:
+ return taskParser.parseTaskCommand(commandWord, arguments);
+
+ case AddDocumentsCommand.COMMAND_WORD:
+ case EditDocumentsCommand.COMMAND_WORD:
+ case DeleteDocumentsCommand.COMMAND_WORD:
+ return documentsParser.parseDocumentsCommand(commandWord, arguments);
+
+ default:
+ throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..e23f3497327 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -2,6 +2,7 @@
import static java.util.Objects.requireNonNull;
+import java.time.LocalDate;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@@ -9,11 +10,24 @@
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.address.model.application.CompanyName;
+import seedu.address.model.application.InternshipStatus;
+import seedu.address.model.application.InterviewDate;
+import seedu.address.model.application.JobTitle;
+import seedu.address.model.application.Location;
+import seedu.address.model.application.Note;
+import seedu.address.model.application.ProgrammingLanguage;
+import seedu.address.model.application.Qualification;
+import seedu.address.model.application.Rating;
+import seedu.address.model.application.Reflection;
+import seedu.address.model.application.Review;
+import seedu.address.model.application.Salary;
+import seedu.address.model.contact.Email;
+import seedu.address.model.contact.Phone;
+import seedu.address.model.documents.CoverLetterLink;
+import seedu.address.model.documents.ResumeLink;
+import seedu.address.model.task.ApplicationDeadline;
+import seedu.address.model.task.NoteContent;
/**
* Contains utility methods used for parsing strings in the various *Parser classes.
@@ -21,6 +35,7 @@
public class ParserUtil {
public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer.";
+ public static final String MESSAGE_INVALID_INTERVAL = "The start date must be before or equal to the end date.";
/**
* Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
@@ -36,18 +51,220 @@ public static Index parseIndex(String oneBasedIndex) throws ParseException {
}
/**
- * Parses a {@code String name} into a {@code Name}.
+ * Parses a {@code String companyName} into a {@code CompanyName}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code name} is invalid.
+ * @throws ParseException if the given {@code companyName} 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 CompanyName parseCompanyName(String companyName) throws ParseException {
+ requireNonNull(companyName);
+ String trimmedName = companyName.trim();
+ if (!CompanyName.isValidCompanyName(trimmedName)) {
+ throw new ParseException(CompanyName.MESSAGE_CONSTRAINTS);
}
- return new Name(trimmedName);
+ return new CompanyName(trimmedName);
+ }
+
+ /**
+ * Parses a {@code String jobTitle} into a {@code JobTitle}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code jobTitle} is invalid.
+ */
+ public static JobTitle parseJobTitle(String jobTitle) throws ParseException {
+ requireNonNull(jobTitle);
+ String trimmedJobTitle = jobTitle.trim();
+ if (!JobTitle.isValidJobTitle(trimmedJobTitle)) {
+ throw new ParseException(JobTitle.MESSAGE_CONSTRAINTS);
+ }
+ return new JobTitle(trimmedJobTitle);
+ }
+
+ /**
+ * Parses a {@code String Review} into a {@code Review}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code review} is invalid.
+ */
+ public static Review parseReview(String review) throws ParseException {
+ requireNonNull(review);
+ String trimmedReview = review.trim();
+ if (!Review.isValidReview(trimmedReview)) {
+ throw new ParseException(Review.MESSAGE_CONSTRAINTS);
+ }
+ return new Review(trimmedReview);
+ }
+
+ /**
+ * Parses {@code Collection reviews} into a {@code Set}.
+ */
+ public static Set parseReviews(Collection reviews) throws ParseException {
+ requireNonNull(reviews);
+ final Set reviewList = new HashSet<>();
+ for (String review : reviews) {
+ reviewList.add(parseReview(review));
+ }
+ return reviewList;
+ }
+
+ /**
+ * Parses a {@code String Programming Language} into a {@code Programming Language}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code programmingLanguage} is invalid.
+ */
+ public static ProgrammingLanguage parseProgrammingLanguage(String programmingLanguage) throws ParseException {
+ requireNonNull(programmingLanguage);
+ String trimmedProgrammingLanguage = programmingLanguage.trim();
+ if (!ProgrammingLanguage.isValidProgrammingLanguage(trimmedProgrammingLanguage)) {
+ throw new ParseException(ProgrammingLanguage.MESSAGE_CONSTRAINTS);
+ }
+ return new ProgrammingLanguage(trimmedProgrammingLanguage);
+ }
+
+ /**
+ * Parses {@code Collection programming languages} into a {@code Set}.
+ */
+ public static Set parseProgrammingLanguages(
+ Collection programmingLanguages) throws ParseException {
+ requireNonNull(programmingLanguages);
+ final Set programmingLanguageList = new HashSet<>();
+ for (String programmingLanguage : programmingLanguages) {
+ programmingLanguageList.add(parseProgrammingLanguage(programmingLanguage));
+ }
+ return programmingLanguageList;
+ }
+
+ /**
+ * Parses a {@code String Qualification} into a {@code Qualification}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code qualification} is invalid.
+ */
+ public static Qualification parseQualification(String qualification) throws ParseException {
+ requireNonNull(qualification);
+ String trimmedQualification = qualification.trim();
+ if (!Qualification.isValidQualification(trimmedQualification)) {
+ throw new ParseException(Qualification.MESSAGE_CONSTRAINTS);
+ }
+ return new Qualification(trimmedQualification);
+ }
+
+ /**
+ * Parses {@code Collection qualifications} into a {@code Set}.
+ */
+ public static Set parseQualifications(Collection qualifications) throws ParseException {
+ requireNonNull(qualifications);
+ final Set qualificationList = new HashSet<>();
+ for (String qualification : qualifications) {
+ qualificationList.add(parseQualification(qualification));
+ }
+ return qualificationList;
+ }
+
+ /**
+ * Parses a {@code String location} into a {@code Location}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code location} is invalid.
+ */
+ public static Location parseLocation(String location) throws ParseException {
+ if (location == null) {
+ return new Location(null);
+ }
+ String trimmedLocation = location.trim();
+ if (!Location.isValidLocation(trimmedLocation)) {
+ throw new ParseException(Location.MESSAGE_CONSTRAINTS);
+ }
+ return new Location(trimmedLocation);
+ }
+
+ /**
+ * Parses a {@code String salary} into a {@code Salary}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code salary} is invalid.
+ */
+ public static Salary parseSalary(String salary) throws ParseException {
+ if (salary == null) {
+ return new Salary(null);
+ }
+ String trimmedSalary = salary.trim();
+ if (!Salary.isValidSalary(trimmedSalary)) {
+ throw new ParseException(Salary.MESSAGE_CONSTRAINTS);
+ }
+ return new Salary(trimmedSalary);
+ }
+
+ /**
+ * Parses a {@code String Note} into a {@code Note}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code note} is invalid.
+ */
+ public static Note parseNote(String note) throws ParseException {
+ requireNonNull(note);
+ String trimmedNote = note.trim();
+ if (!Note.isValidNote(trimmedNote)) {
+ throw new ParseException(Note.MESSAGE_CONSTRAINTS);
+ }
+ return new Note(trimmedNote);
+ }
+
+ /**
+ * Parses {@code Collection notes} into a {@code Set}.
+ */
+ public static Set parseNotes(Collection notes) throws ParseException {
+ requireNonNull(notes);
+ final Set noteList = new HashSet<>();
+ for (String note : notes) {
+ noteList.add(parseNote(note));
+ }
+ return noteList;
+ }
+
+ /**
+ * Parses a {@code String rating} into a {@code Rating}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code rating} is invalid.
+ */
+ public static Rating parseRating(String rating) throws ParseException {
+ if (rating == null) {
+ return new Rating(null);
+ }
+ String trimmedRating = rating.trim();
+ if (!Rating.isValidRating(trimmedRating)) {
+ throw new ParseException(Rating.MESSAGE_CONSTRAINTS);
+ }
+ return new Rating(trimmedRating);
+ }
+
+ /**
+ * Parses a {@code String Reflection} into a {@code Reflection}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code reflection} is invalid.
+ */
+ public static Reflection parseReflection(String reflection) throws ParseException {
+ requireNonNull(reflection);
+ String trimmedReflection = reflection.trim();
+ if (!Reflection.isValidReflection(trimmedReflection)) {
+ throw new ParseException(Reflection.MESSAGE_CONSTRAINTS);
+ }
+ return new Reflection(trimmedReflection);
+ }
+
+ /**
+ * Parses {@code Collection reflections} into a {@code Set}.
+ */
+ public static Set parseReflections(Collection reflections) throws ParseException {
+ requireNonNull(reflections);
+ final Set reflectionList = new HashSet<>();
+ for (String reflection : reflections) {
+ reflectionList.add(parseReflection(reflection));
+ }
+ return reflectionList;
}
/**
@@ -65,21 +282,6 @@ public static Phone parsePhone(String phone) throws ParseException {
return new Phone(trimmedPhone);
}
- /**
- * 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}.
* Leading and trailing whitespaces will be trimmed.
@@ -96,29 +298,92 @@ public static Email parseEmail(String email) throws ParseException {
}
/**
- * Parses a {@code String tag} into a {@code Tag}.
+ * Parses a {@code String interviewDate} into an {@code InterviewDate}.
+ * Leading and trailing whitespaces will be trimmed.
+ */
+ public static InterviewDate parseInterviewDate(String interviewDate) {
+ requireNonNull(interviewDate);
+ String trimmedInterviewDate = interviewDate.trim();
+ return new InterviewDate(interviewDate);
+ }
+
+ /**
+ * Parses a {@code String status} into a {@code InternshipStatus}.
+ * Leading and trailing whitespaces will be trimmed. It's case-insensitive
+ *
+ * @throws ParseException if the given {@code status} is invalid.
+ */
+ public static InternshipStatus parseInternshipStatus(String status) throws ParseException {
+ requireNonNull(status);
+ String trimmedStatus = status.trim().toUpperCase();
+ if (!InternshipStatus.isValidStatus(trimmedStatus)) {
+ throw new ParseException(InternshipStatus.MESSAGE_CONSTRAINTS);
+ }
+ return InternshipStatus.valueOf(trimmedStatus);
+ }
+
+ /**
+ * Parses a {@code String deadline} into a {@code ApplicationDeadline}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code deadline} is invalid.
+ */
+ public static ApplicationDeadline parseDeadline(String deadline) throws ParseException {
+ requireNonNull(deadline);
+
+ String trimmedDeadline = deadline.trim();
+ LocalDate formattedDate = LocalDate.parse(trimmedDeadline);
+
+ if (!ApplicationDeadline.isValidDate(formattedDate)) {
+ throw new ParseException(ApplicationDeadline.MESSAGE_CONSTRAINTS);
+ }
+ return new ApplicationDeadline(formattedDate);
+ }
+
+ /**
+ * Parses a {@code String content} into a {@code NoteContent}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code content} is invalid.
+ */
+ public static NoteContent parseContent(String content) throws ParseException {
+ requireNonNull(content);
+
+ String trimmedContent = content.trim();
+
+ if (!NoteContent.isValidContent(content)) {
+ throw new ParseException(NoteContent.MESSAGE_CONSTRAINTS);
+ }
+ return new NoteContent(trimmedContent);
+ }
+
+ /**
+ * Parses a {@code String status} into a {@code ResumeLink}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code tag} is invalid.
+ * @throws ParseException if the given {@code status} is invalid.
*/
- public static Tag parseTag(String tag) throws ParseException {
- requireNonNull(tag);
- String trimmedTag = tag.trim();
- if (!Tag.isValidTagName(trimmedTag)) {
- throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
+ public static ResumeLink parseResumeLink(String status) throws ParseException {
+ requireNonNull(status);
+ String trimmedStatus = status.trim();
+ if (!ResumeLink.isValidResumeLink(trimmedStatus)) {
+ throw new ParseException(ResumeLink.MESSAGE_CONSTRAINTS);
}
- return new Tag(trimmedTag);
+ return new ResumeLink(trimmedStatus);
}
/**
- * Parses {@code Collection tags} into a {@code Set}.
+ * Parses a {@code String status} into a {@code CoverLetterLink}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code status} is invalid.
*/
- public static Set parseTags(Collection tags) throws ParseException {
- requireNonNull(tags);
- final Set tagSet = new HashSet<>();
- for (String tagName : tags) {
- tagSet.add(parseTag(tagName));
+ public static CoverLetterLink parseCoverLetterLink(String status) throws ParseException {
+ requireNonNull(status);
+ String trimmedStatus = status.trim();
+ if (!CoverLetterLink.isValidCoverLetterLink(trimmedStatus)) {
+ throw new ParseException(CoverLetterLink.MESSAGE_CONSTRAINTS);
}
- return tagSet;
+ return new CoverLetterLink(trimmedStatus);
}
}
diff --git a/src/main/java/seedu/address/logic/parser/SortCommandParser.java b/src/main/java/seedu/address/logic/parser/SortCommandParser.java
new file mode 100644
index 00000000000..88d7bcea7bb
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/SortCommandParser.java
@@ -0,0 +1,67 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_JOB_TITLE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_STATUS;
+
+import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.SortCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.application.comparator.CompanyNameComparator;
+import seedu.address.model.application.comparator.InterviewDateComparator;
+import seedu.address.model.application.comparator.JobTitleComparator;
+import seedu.address.model.application.comparator.StatusComparator;
+
+/**
+ * Parses input arguments and creates a new FindCommand object
+ */
+public class SortCommandParser implements Parser {
+
+ /**
+ * Checks if the prefix p specified is valid.
+ *
+ * @param p The prefix to be verified
+ * @throws ParseException if none of the prefixes is matched
+ */
+ private void verifySortCommandOptions(Prefix p) throws ParseException {
+ for (Prefix i : SortCommand.PREFIXES_SUPPORTED) {
+ if (p.equals(i)) {
+ return;
+ }
+ }
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the SortCommand
+ * and returns a SortCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public SortCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortCommand.MESSAGE_USAGE));
+ }
+ String[] prefixes = trimmedArgs.split("\\s+");
+ if (prefixes.length != 1) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+ Prefix prefix = new Prefix(prefixes[0]);
+ verifySortCommandOptions(prefix);
+ if (PREFIX_COMPANY_NAME.equals(prefix)) {
+ return new SortCommand(new CompanyNameComparator());
+ } else if (PREFIX_JOB_TITLE.equals(prefix)) {
+ return new SortCommand(new JobTitleComparator());
+ } else if (PREFIX_STATUS.equals(prefix)) {
+ return new SortCommand(new StatusComparator());
+ } else if (PREFIX_DATE.equals(prefix)) {
+ return new SortCommand(new InterviewDateComparator());
+ }
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/logic/parser/UnarchiveCommandParser.java b/src/main/java/seedu/address/logic/parser/UnarchiveCommandParser.java
new file mode 100644
index 00000000000..8e0f0b2259b
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/UnarchiveCommandParser.java
@@ -0,0 +1,29 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.UnarchiveCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new UnarchiveCommand object
+ */
+public class UnarchiveCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the UnarchiveCommand
+ * and returns a UnarchiveCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public UnarchiveCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new UnarchiveCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnarchiveCommand.MESSAGE_USAGE), pe);
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/contact/AddContactCommandParser.java b/src/main/java/seedu/address/logic/parser/contact/AddContactCommandParser.java
new file mode 100644
index 00000000000..32579b15e17
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/contact/AddContactCommandParser.java
@@ -0,0 +1,65 @@
+package seedu.address.logic.parser.contact;
+
+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_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.contact.AddContactCommand;
+import seedu.address.logic.parser.ArgumentMultimap;
+import seedu.address.logic.parser.ArgumentTokenizer;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.Prefix;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.contact.Contact;
+import seedu.address.model.contact.Email;
+import seedu.address.model.contact.Phone;
+
+/**
+* Parses input arguments and creates a new AddContactCommand object
+*/
+public class AddContactCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddContactCommand
+ * and returns an AddContactCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddContactCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_PHONE, PREFIX_EMAIL);
+
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddContactCommand.MESSAGE_USAGE),
+ pe);
+ }
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_PHONE, PREFIX_EMAIL)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddContactCommand.MESSAGE_USAGE));
+ }
+
+ Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
+ Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
+
+ Contact contact = new Contact(phone, email);
+
+ return new AddContactCommand(index, contact);
+ }
+
+ /**
+ * 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/contact/ContactParser.java b/src/main/java/seedu/address/logic/parser/contact/ContactParser.java
new file mode 100644
index 00000000000..ae32de53582
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/contact/ContactParser.java
@@ -0,0 +1,39 @@
+package seedu.address.logic.parser.contact;
+
+import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.contact.AddContactCommand;
+import seedu.address.logic.commands.contact.DeleteContactCommand;
+import seedu.address.logic.commands.contact.EditContactCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses user input related to task package.
+ */
+public class ContactParser {
+
+ /**
+ * Parses user input into task related command for execution.
+ *
+ * @param commandWord command word in user input
+ * @param arguments command argument related to specified parameter types
+ * @return the command based on the user input
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public Command parseContactCommand(String commandWord, String arguments) throws ParseException {
+ switch (commandWord) {
+ case AddContactCommand.COMMAND_WORD:
+ return new AddContactCommandParser().parse(arguments);
+
+ case EditContactCommand.COMMAND_WORD:
+ return new EditContactCommandParser().parse(arguments);
+
+ case DeleteContactCommand.COMMAND_WORD:
+ return new DeleteContactCommandParser().parse(arguments);
+
+ default:
+ throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/contact/DeleteContactCommandParser.java b/src/main/java/seedu/address/logic/parser/contact/DeleteContactCommandParser.java
new file mode 100644
index 00000000000..07ef5fe9e7e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/contact/DeleteContactCommandParser.java
@@ -0,0 +1,29 @@
+package seedu.address.logic.parser.contact;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.contact.DeleteContactCommand;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new DeleteContactCommand object
+ */
+public class DeleteContactCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteContactCommand
+ * and returns a DeleteContactCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteContactCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new DeleteContactCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteContactCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/contact/EditContactCommandParser.java b/src/main/java/seedu/address/logic/parser/contact/EditContactCommandParser.java
new file mode 100644
index 00000000000..510934c753d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/contact/EditContactCommandParser.java
@@ -0,0 +1,68 @@
+package seedu.address.logic.parser.contact;
+
+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_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.contact.EditContactCommand;
+import seedu.address.logic.parser.ArgumentMultimap;
+import seedu.address.logic.parser.ArgumentTokenizer;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.Prefix;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new EditContactCommand object
+ */
+public class EditContactCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditContactCommand
+ * and returns an EditContactCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public EditContactCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_PHONE, PREFIX_EMAIL);
+
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditContactCommand.MESSAGE_USAGE),
+ pe);
+ }
+
+ EditContactCommand.EditContactDescriptor editDocumentsDescriptor =
+ new EditContactCommand.EditContactDescriptor();
+ if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
+ editDocumentsDescriptor.setPhone(
+ ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
+ editDocumentsDescriptor.setEmail(
+ ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
+ }
+
+ if (!editDocumentsDescriptor.isAnyFieldEdited()) {
+ throw new ParseException(EditContactCommand.MESSAGE_NOT_EDITED);
+ }
+
+ return new EditContactCommand(index, editDocumentsDescriptor);
+ }
+
+ /**
+ * 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/documents/AddDocumentsCommandParser.java b/src/main/java/seedu/address/logic/parser/documents/AddDocumentsCommandParser.java
new file mode 100644
index 00000000000..3a6264258f4
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/documents/AddDocumentsCommandParser.java
@@ -0,0 +1,66 @@
+package seedu.address.logic.parser.documents;
+
+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_COVER_LETTER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_RESUME;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.documents.AddDocumentsCommand;
+import seedu.address.logic.parser.ArgumentMultimap;
+import seedu.address.logic.parser.ArgumentTokenizer;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.Prefix;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.documents.CoverLetterLink;
+import seedu.address.model.documents.Documents;
+import seedu.address.model.documents.ResumeLink;
+
+/**
+ * Parses input arguments and creates a new AddContactCommand object
+ */
+public class AddDocumentsCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddContactCommand
+ * and returns an AddContactCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddDocumentsCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_RESUME, PREFIX_COVER_LETTER);
+
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddDocumentsCommand.MESSAGE_USAGE),
+ pe);
+ }
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_RESUME, PREFIX_COVER_LETTER)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddDocumentsCommand.MESSAGE_USAGE));
+ }
+
+ ResumeLink resumeLink = ParserUtil.parseResumeLink(argMultimap.getValue(PREFIX_RESUME).get());
+ CoverLetterLink coverLetterLink = ParserUtil.parseCoverLetterLink(argMultimap.getValue(PREFIX_COVER_LETTER)
+ .get());
+
+ Documents documents = new Documents(resumeLink, coverLetterLink);
+
+ return new AddDocumentsCommand(index, documents);
+ }
+
+ /**
+ * 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/documents/DeleteDocumentsCommandParser.java b/src/main/java/seedu/address/logic/parser/documents/DeleteDocumentsCommandParser.java
new file mode 100644
index 00000000000..7da4397b06f
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/documents/DeleteDocumentsCommandParser.java
@@ -0,0 +1,29 @@
+package seedu.address.logic.parser.documents;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.documents.DeleteDocumentsCommand;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new DeleteDocumentsCommand object
+ */
+public class DeleteDocumentsCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteDocumentsCommand
+ * and returns a DeleteDocumentsCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteDocumentsCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new DeleteDocumentsCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteDocumentsCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/documents/DocumentsParser.java b/src/main/java/seedu/address/logic/parser/documents/DocumentsParser.java
new file mode 100644
index 00000000000..4696db3ba9e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/documents/DocumentsParser.java
@@ -0,0 +1,43 @@
+package seedu.address.logic.parser.documents;
+
+import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+
+import java.util.regex.Pattern;
+
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.documents.AddDocumentsCommand;
+import seedu.address.logic.commands.documents.DeleteDocumentsCommand;
+import seedu.address.logic.commands.documents.EditDocumentsCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses user input for commands related to documents.
+ */
+public class DocumentsParser {
+ /**
+ * Used for initial separation of command word and args.
+ */
+ private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)");
+
+ /**
+ * Parses user input into command for execution.
+ *
+ * @return the command based on the user input
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public Command parseDocumentsCommand(String commandWord, String arguments) throws ParseException {
+ switch (commandWord) {
+ case AddDocumentsCommand.COMMAND_WORD:
+ return new AddDocumentsCommandParser().parse(arguments);
+
+ case EditDocumentsCommand.COMMAND_WORD:
+ return new EditDocumentsCommandParser().parse(arguments);
+
+ case DeleteDocumentsCommand.COMMAND_WORD:
+ return new DeleteDocumentsCommandParser().parse(arguments);
+
+ default:
+ throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/documents/EditDocumentsCommandParser.java b/src/main/java/seedu/address/logic/parser/documents/EditDocumentsCommandParser.java
new file mode 100644
index 00000000000..33683e61ad6
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/documents/EditDocumentsCommandParser.java
@@ -0,0 +1,68 @@
+package seedu.address.logic.parser.documents;
+
+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_COVER_LETTER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_RESUME;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.documents.EditDocumentsCommand;
+import seedu.address.logic.parser.ArgumentMultimap;
+import seedu.address.logic.parser.ArgumentTokenizer;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.Prefix;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new EditDocumentsCommand object
+ */
+public class EditDocumentsCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditDocumentsCommand
+ * and returns an EditDocumentsCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public EditDocumentsCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_RESUME, PREFIX_COVER_LETTER);
+
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditDocumentsCommand.MESSAGE_USAGE),
+ pe);
+ }
+
+ EditDocumentsCommand.EditDocumentsDescriptor editDocumentsDescriptor =
+ new EditDocumentsCommand.EditDocumentsDescriptor();
+ if (argMultimap.getValue(PREFIX_RESUME).isPresent()) {
+ editDocumentsDescriptor.setResumeLink(
+ ParserUtil.parseResumeLink(argMultimap.getValue(PREFIX_RESUME).get()));
+ }
+ if (argMultimap.getValue(PREFIX_COVER_LETTER).isPresent()) {
+ editDocumentsDescriptor.setCoverLetterLink(
+ ParserUtil.parseCoverLetterLink(argMultimap.getValue(PREFIX_COVER_LETTER).get()));
+ }
+
+ if (!editDocumentsDescriptor.isAnyFieldEdited()) {
+ throw new ParseException(EditDocumentsCommand.MESSAGE_NOT_EDITED);
+ }
+
+ return new EditDocumentsCommand(index, editDocumentsDescriptor);
+ }
+
+ /**
+ * 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/task/FindTaskCommandParser.java b/src/main/java/seedu/address/logic/parser/task/FindTaskCommandParser.java
new file mode 100644
index 00000000000..d00aa489472
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/task/FindTaskCommandParser.java
@@ -0,0 +1,42 @@
+package seedu.address.logic.parser.task;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Arrays;
+
+import seedu.address.logic.commands.task.FindTaskCommand;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.task.ContentContainsKeywordsPredicate;
+import seedu.address.model.task.TitleContainsKeywordsPredicate;
+
+
+/**
+ * Parses input arguments and creates a new FindTaskCommand object
+ */
+public class FindTaskCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindTaskCommand
+ * and returns a FindTaskCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindTaskCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindTaskCommand.MESSAGE_USAGE));
+ }
+
+ String[] nameKeywords = trimmedArgs.split("\\s+");
+
+ TitleContainsKeywordsPredicate titlePredicate = new TitleContainsKeywordsPredicate(
+ Arrays.asList(nameKeywords));
+ ContentContainsKeywordsPredicate contentPredicate = new ContentContainsKeywordsPredicate(
+ Arrays.asList(nameKeywords));
+
+ return new FindTaskCommand(titlePredicate, contentPredicate);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/task/TaskParser.java b/src/main/java/seedu/address/logic/parser/task/TaskParser.java
new file mode 100644
index 00000000000..334d23794f3
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/task/TaskParser.java
@@ -0,0 +1,107 @@
+package seedu.address.logic.parser.task;
+
+import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.task.FindTaskCommand;
+import seedu.address.logic.commands.task.ListTaskCommand;
+import seedu.address.logic.commands.task.note.AddNoteCommand;
+import seedu.address.logic.commands.task.note.ClearNoteCommand;
+import seedu.address.logic.commands.task.note.DeleteNoteCommand;
+import seedu.address.logic.commands.task.note.ListNoteCommand;
+import seedu.address.logic.commands.task.todo.AddTodoCommand;
+import seedu.address.logic.commands.task.todo.ClearTodoCommand;
+import seedu.address.logic.commands.task.todo.DeleteTodoCommand;
+import seedu.address.logic.commands.task.todo.EditDeadlineCommand;
+import seedu.address.logic.commands.task.todo.EditNoteContentCommand;
+import seedu.address.logic.commands.task.todo.ListTodoCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.logic.parser.task.note.AddNoteCommandParser;
+import seedu.address.logic.parser.task.note.DeleteNoteCommandParser;
+import seedu.address.logic.parser.task.todo.AddTodoCommandParser;
+import seedu.address.logic.parser.task.todo.DeleteTodoCommandParser;
+import seedu.address.logic.parser.task.todo.EditContentCommandParser;
+import seedu.address.logic.parser.task.todo.EditDeadlineCommandParser;
+
+/**
+ * Parses user inputs related to the task package.
+ */
+public class TaskParser {
+
+ /**
+ * Parses user input into task related command according to the {@code commandWord} with the {@code arguments} for
+ * execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public Command parseTaskCommand(String commandWord, String arguments) throws ParseException {
+ switch (commandWord) {
+ case ListTaskCommand.COMMAND_WORD:
+ return new ListTaskCommand();
+
+ case FindTaskCommand.COMMAND_WORD:
+ return new FindTaskCommandParser().parse(arguments);
+
+ case AddTodoCommand.COMMAND_WORD:
+ case ListTodoCommand.COMMAND_WORD:
+ case EditDeadlineCommand.COMMAND_WORD:
+ case EditNoteContentCommand.COMMAND_WORD:
+ case DeleteTodoCommand.COMMAND_WORD:
+ case ClearTodoCommand.COMMAND_WORD:
+ return parseTodoCommand(commandWord, arguments);
+
+ case AddNoteCommand.COMMAND_WORD:
+ case ListNoteCommand.COMMAND_WORD:
+ case DeleteNoteCommand.COMMAND_WORD:
+ case ClearNoteCommand.COMMAND_WORD:
+ return parseNoteCommand(commandWord, arguments);
+
+ default:
+ throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
+ }
+ }
+
+ private Command parseTodoCommand(String commandWord, String arguments) throws ParseException {
+ switch (commandWord) {
+ case AddTodoCommand.COMMAND_WORD:
+ return new AddTodoCommandParser().parse(arguments);
+
+ case ListTodoCommand.COMMAND_WORD:
+ return new ListTodoCommand();
+
+ case EditDeadlineCommand.COMMAND_WORD:
+ return new EditDeadlineCommandParser().parse(arguments);
+
+ case EditNoteContentCommand.COMMAND_WORD:
+ return new EditContentCommandParser().parse(arguments);
+
+ case DeleteTodoCommand.COMMAND_WORD:
+ return new DeleteTodoCommandParser().parse(arguments);
+
+ case ClearTodoCommand.COMMAND_WORD:
+ return new ClearTodoCommand();
+
+ default:
+ throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
+ }
+ }
+
+ private Command parseNoteCommand(String commandWord, String arguments) throws ParseException {
+ switch (commandWord) {
+ case AddNoteCommand.COMMAND_WORD:
+ return new AddNoteCommandParser().parse(arguments);
+
+ case ListNoteCommand.COMMAND_WORD:
+ return new ListNoteCommand();
+
+ case DeleteNoteCommand.COMMAND_WORD:
+ return new DeleteNoteCommandParser().parse(arguments);
+
+ case ClearNoteCommand.COMMAND_WORD:
+ return new ClearNoteCommand();
+
+ default:
+ throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/task/note/AddNoteCommandParser.java b/src/main/java/seedu/address/logic/parser/task/note/AddNoteCommandParser.java
new file mode 100644
index 00000000000..d53b986231f
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/task/note/AddNoteCommandParser.java
@@ -0,0 +1,53 @@
+package seedu.address.logic.parser.task.note;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NOTE_CONTENT;
+
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.task.note.AddNoteCommand;
+import seedu.address.logic.parser.ArgumentMultimap;
+import seedu.address.logic.parser.ArgumentTokenizer;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.Prefix;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.task.Note;
+import seedu.address.model.task.NoteContent;
+
+/**
+ * Parses input arguments and creates a new AddNoteCommand object
+ */
+public class AddNoteCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddNoteCommand
+ * and returns an AddNoteCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddNoteCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_NOTE_CONTENT);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_NOTE_CONTENT)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddNoteCommand.MESSAGE_USAGE));
+ }
+
+ NoteContent content = ParserUtil.parseContent(argMultimap.getValue(PREFIX_NOTE_CONTENT).orElse(null));
+
+
+ Note note = new Note(content);
+
+ return new AddNoteCommand(note);
+ }
+
+ /**
+ * 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/task/note/DeleteNoteCommandParser.java b/src/main/java/seedu/address/logic/parser/task/note/DeleteNoteCommandParser.java
new file mode 100644
index 00000000000..69da31dfe42
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/task/note/DeleteNoteCommandParser.java
@@ -0,0 +1,32 @@
+package seedu.address.logic.parser.task.note;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.task.note.DeleteNoteCommand;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new DeleteNoteCommand object
+ */
+public class DeleteNoteCommandParser implements Parser