diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000000..050505ce79e
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "java.configuration.updateBuildConfiguration": "interactive"
+}
diff --git a/README.md b/README.md
index 16208adb9b6..82889ae177d 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,18 @@
-[](https://github.com/se-edu/addressbook-level3/actions)
+# HRelper
+
+[](https://github.com/AY2425S2-CS2103T-F14-2/tp/actions)

+
-* This is **a sample project for Software Engineering (SE) students**.
+* This project is based on the **AddressBook-Level3 project** created by the [SE-EDU initiative](https://se-education.org).
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` ...).
+* It is named `HRelper`, and it is specially designed for HRs of companies, to enable HRs to quickly access and manage employee and job seeker information, streamlining recruitment and communication within the company.
* 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/#contributing-to-se-edu) for more info.
+🐌
diff --git a/bin/main/images/address_book_32.png b/bin/main/images/address_book_32.png
new file mode 100644
index 00000000000..29810cf1fd9
Binary files /dev/null and b/bin/main/images/address_book_32.png differ
diff --git a/bin/main/images/calendar.png b/bin/main/images/calendar.png
new file mode 100644
index 00000000000..8b2bdf4f1c1
Binary files /dev/null and b/bin/main/images/calendar.png differ
diff --git a/bin/main/images/clock.png b/bin/main/images/clock.png
new file mode 100644
index 00000000000..0807cbf6451
Binary files /dev/null and b/bin/main/images/clock.png differ
diff --git a/bin/main/images/fail.png b/bin/main/images/fail.png
new file mode 100644
index 00000000000..6daf01290dd
Binary files /dev/null and b/bin/main/images/fail.png differ
diff --git a/bin/main/images/help_icon.png b/bin/main/images/help_icon.png
new file mode 100644
index 00000000000..f8e80d6c1c5
Binary files /dev/null and b/bin/main/images/help_icon.png differ
diff --git a/bin/main/images/info_icon.png b/bin/main/images/info_icon.png
new file mode 100644
index 00000000000..f8cef714095
Binary files /dev/null and b/bin/main/images/info_icon.png differ
diff --git a/bin/main/seedu/address/AppParameters.class b/bin/main/seedu/address/AppParameters.class
new file mode 100644
index 00000000000..a849196488f
Binary files /dev/null and b/bin/main/seedu/address/AppParameters.class differ
diff --git a/bin/main/seedu/address/Main.class b/bin/main/seedu/address/Main.class
new file mode 100644
index 00000000000..aeb70e4d0c3
Binary files /dev/null and b/bin/main/seedu/address/Main.class differ
diff --git a/bin/main/seedu/address/MainApp.class b/bin/main/seedu/address/MainApp.class
new file mode 100644
index 00000000000..27a0cf08822
Binary files /dev/null and b/bin/main/seedu/address/MainApp.class differ
diff --git a/bin/main/seedu/address/commons/core/Config.class b/bin/main/seedu/address/commons/core/Config.class
new file mode 100644
index 00000000000..e77db5acc9e
Binary files /dev/null and b/bin/main/seedu/address/commons/core/Config.class differ
diff --git a/bin/main/seedu/address/commons/core/GuiSettings.class b/bin/main/seedu/address/commons/core/GuiSettings.class
new file mode 100644
index 00000000000..b6e9d4e5dbb
Binary files /dev/null and b/bin/main/seedu/address/commons/core/GuiSettings.class differ
diff --git a/bin/main/seedu/address/commons/core/LogsCenter.class b/bin/main/seedu/address/commons/core/LogsCenter.class
new file mode 100644
index 00000000000..916a21ae0e3
Binary files /dev/null and b/bin/main/seedu/address/commons/core/LogsCenter.class differ
diff --git a/bin/main/seedu/address/commons/core/Version.class b/bin/main/seedu/address/commons/core/Version.class
new file mode 100644
index 00000000000..60acbe72e0f
Binary files /dev/null and b/bin/main/seedu/address/commons/core/Version.class differ
diff --git a/bin/main/seedu/address/commons/core/index/Index.class b/bin/main/seedu/address/commons/core/index/Index.class
new file mode 100644
index 00000000000..fa6a9cefcd1
Binary files /dev/null and b/bin/main/seedu/address/commons/core/index/Index.class differ
diff --git a/bin/main/seedu/address/commons/exceptions/DataLoadingException.class b/bin/main/seedu/address/commons/exceptions/DataLoadingException.class
new file mode 100644
index 00000000000..1f1054ff245
Binary files /dev/null and b/bin/main/seedu/address/commons/exceptions/DataLoadingException.class differ
diff --git a/bin/main/seedu/address/commons/exceptions/IllegalValueException.class b/bin/main/seedu/address/commons/exceptions/IllegalValueException.class
new file mode 100644
index 00000000000..5c3b4bb191d
Binary files /dev/null and b/bin/main/seedu/address/commons/exceptions/IllegalValueException.class differ
diff --git a/bin/main/seedu/address/commons/util/AppUtil.class b/bin/main/seedu/address/commons/util/AppUtil.class
new file mode 100644
index 00000000000..2aaa17fc264
Binary files /dev/null and b/bin/main/seedu/address/commons/util/AppUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/CollectionUtil.class b/bin/main/seedu/address/commons/util/CollectionUtil.class
new file mode 100644
index 00000000000..c641cde7527
Binary files /dev/null and b/bin/main/seedu/address/commons/util/CollectionUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/ConfigUtil.class b/bin/main/seedu/address/commons/util/ConfigUtil.class
new file mode 100644
index 00000000000..143f4ebd0ca
Binary files /dev/null and b/bin/main/seedu/address/commons/util/ConfigUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/FileUtil.class b/bin/main/seedu/address/commons/util/FileUtil.class
new file mode 100644
index 00000000000..60c284f41b4
Binary files /dev/null and b/bin/main/seedu/address/commons/util/FileUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/JsonUtil$LevelDeserializer.class b/bin/main/seedu/address/commons/util/JsonUtil$LevelDeserializer.class
new file mode 100644
index 00000000000..1d6d6b0a0c0
Binary files /dev/null and b/bin/main/seedu/address/commons/util/JsonUtil$LevelDeserializer.class differ
diff --git a/bin/main/seedu/address/commons/util/JsonUtil.class b/bin/main/seedu/address/commons/util/JsonUtil.class
new file mode 100644
index 00000000000..1a727d5843f
Binary files /dev/null and b/bin/main/seedu/address/commons/util/JsonUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/StringUtil.class b/bin/main/seedu/address/commons/util/StringUtil.class
new file mode 100644
index 00000000000..d4de4f01220
Binary files /dev/null and b/bin/main/seedu/address/commons/util/StringUtil.class differ
diff --git a/bin/main/seedu/address/commons/util/ToStringBuilder.class b/bin/main/seedu/address/commons/util/ToStringBuilder.class
new file mode 100644
index 00000000000..f378e40adc2
Binary files /dev/null and b/bin/main/seedu/address/commons/util/ToStringBuilder.class differ
diff --git a/bin/main/seedu/address/logic/Logic.class b/bin/main/seedu/address/logic/Logic.class
new file mode 100644
index 00000000000..e33d1582f6b
Binary files /dev/null and b/bin/main/seedu/address/logic/Logic.class differ
diff --git a/bin/main/seedu/address/logic/LogicManager.class b/bin/main/seedu/address/logic/LogicManager.class
new file mode 100644
index 00000000000..9699fad8b28
Binary files /dev/null and b/bin/main/seedu/address/logic/LogicManager.class differ
diff --git a/bin/main/seedu/address/logic/Messages.class b/bin/main/seedu/address/logic/Messages.class
new file mode 100644
index 00000000000..548ef53f2d7
Binary files /dev/null and b/bin/main/seedu/address/logic/Messages.class differ
diff --git a/bin/main/seedu/address/logic/commands/AddCommand.class b/bin/main/seedu/address/logic/commands/AddCommand.class
new file mode 100644
index 00000000000..2622dd697e2
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/AddCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/ClearCommand.class b/bin/main/seedu/address/logic/commands/ClearCommand.class
new file mode 100644
index 00000000000..70623988138
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/ClearCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/Command.class b/bin/main/seedu/address/logic/commands/Command.class
new file mode 100644
index 00000000000..c9db35e1710
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/Command.class differ
diff --git a/bin/main/seedu/address/logic/commands/CommandResult.class b/bin/main/seedu/address/logic/commands/CommandResult.class
new file mode 100644
index 00000000000..16e675869bb
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/CommandResult.class differ
diff --git a/bin/main/seedu/address/logic/commands/DeleteCommand.class b/bin/main/seedu/address/logic/commands/DeleteCommand.class
new file mode 100644
index 00000000000..c2172c890ab
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/DeleteCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/EditCommand$EditPersonDescriptor.class b/bin/main/seedu/address/logic/commands/EditCommand$EditPersonDescriptor.class
new file mode 100644
index 00000000000..d7fe457a2a8
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/EditCommand$EditPersonDescriptor.class differ
diff --git a/bin/main/seedu/address/logic/commands/EditCommand.class b/bin/main/seedu/address/logic/commands/EditCommand.class
new file mode 100644
index 00000000000..ff538c4bc4b
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/EditCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/ExitCommand.class b/bin/main/seedu/address/logic/commands/ExitCommand.class
new file mode 100644
index 00000000000..bf2f455506f
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/ExitCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/FindByDepartmentCommand.class b/bin/main/seedu/address/logic/commands/FindByDepartmentCommand.class
new file mode 100644
index 00000000000..9f925e92470
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/FindByDepartmentCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/FindByEmploymentTypeCommand.class b/bin/main/seedu/address/logic/commands/FindByEmploymentTypeCommand.class
new file mode 100644
index 00000000000..f735d741a22
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/FindByEmploymentTypeCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/FindByJobTitleCommand.class b/bin/main/seedu/address/logic/commands/FindByJobTitleCommand.class
new file mode 100644
index 00000000000..377879b519d
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/FindByJobTitleCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/FindCommand.class b/bin/main/seedu/address/logic/commands/FindCommand.class
new file mode 100644
index 00000000000..1bce4cdbcf6
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/FindCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/HelpCommand.class b/bin/main/seedu/address/logic/commands/HelpCommand.class
new file mode 100644
index 00000000000..98c306e14d4
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/HelpCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/ListCommand.class b/bin/main/seedu/address/logic/commands/ListCommand.class
new file mode 100644
index 00000000000..c751adae8b1
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/ListCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/NoteCommand.class b/bin/main/seedu/address/logic/commands/NoteCommand.class
new file mode 100644
index 00000000000..b26bf574869
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/NoteCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/ViewCommand.class b/bin/main/seedu/address/logic/commands/ViewCommand.class
new file mode 100644
index 00000000000..c216b307731
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/ViewCommand.class differ
diff --git a/bin/main/seedu/address/logic/commands/exceptions/CommandException.class b/bin/main/seedu/address/logic/commands/exceptions/CommandException.class
new file mode 100644
index 00000000000..3c13e77f966
Binary files /dev/null and b/bin/main/seedu/address/logic/commands/exceptions/CommandException.class differ
diff --git a/bin/main/seedu/address/logic/parser/AddCommandParser.class b/bin/main/seedu/address/logic/parser/AddCommandParser.class
new file mode 100644
index 00000000000..ea6e473d173
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/AddCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/AddressBookParser.class b/bin/main/seedu/address/logic/parser/AddressBookParser.class
new file mode 100644
index 00000000000..2ffc31d36fa
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/AddressBookParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/ArgumentMultimap.class b/bin/main/seedu/address/logic/parser/ArgumentMultimap.class
new file mode 100644
index 00000000000..6ec597022aa
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/ArgumentMultimap.class differ
diff --git a/bin/main/seedu/address/logic/parser/ArgumentTokenizer$PrefixPosition.class b/bin/main/seedu/address/logic/parser/ArgumentTokenizer$PrefixPosition.class
new file mode 100644
index 00000000000..6a5b47712d6
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/ArgumentTokenizer$PrefixPosition.class differ
diff --git a/bin/main/seedu/address/logic/parser/ArgumentTokenizer.class b/bin/main/seedu/address/logic/parser/ArgumentTokenizer.class
new file mode 100644
index 00000000000..578c11267cf
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/ArgumentTokenizer.class differ
diff --git a/bin/main/seedu/address/logic/parser/CliSyntax.class b/bin/main/seedu/address/logic/parser/CliSyntax.class
new file mode 100644
index 00000000000..7a63b8a27f1
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/CliSyntax.class differ
diff --git a/bin/main/seedu/address/logic/parser/DeleteCommandParser.class b/bin/main/seedu/address/logic/parser/DeleteCommandParser.class
new file mode 100644
index 00000000000..9e84a714aee
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/DeleteCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/EditCommandParser.class b/bin/main/seedu/address/logic/parser/EditCommandParser.class
new file mode 100644
index 00000000000..fef4e2029a2
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/EditCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/FindByDepartmentCommandParser.class b/bin/main/seedu/address/logic/parser/FindByDepartmentCommandParser.class
new file mode 100644
index 00000000000..92b6785502c
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/FindByDepartmentCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/FindByEmploymentTypeCommandParser.class b/bin/main/seedu/address/logic/parser/FindByEmploymentTypeCommandParser.class
new file mode 100644
index 00000000000..fcb8019cb38
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/FindByEmploymentTypeCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/FindByJobTitleCommandParser.class b/bin/main/seedu/address/logic/parser/FindByJobTitleCommandParser.class
new file mode 100644
index 00000000000..3ea112a19e2
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/FindByJobTitleCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/FindCommandParser.class b/bin/main/seedu/address/logic/parser/FindCommandParser.class
new file mode 100644
index 00000000000..39b0e2ca391
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/FindCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/NoteCommandParser.class b/bin/main/seedu/address/logic/parser/NoteCommandParser.class
new file mode 100644
index 00000000000..51214696bc0
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/NoteCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/Parser.class b/bin/main/seedu/address/logic/parser/Parser.class
new file mode 100644
index 00000000000..850c8a46a9b
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/Parser.class differ
diff --git a/bin/main/seedu/address/logic/parser/ParserUtil.class b/bin/main/seedu/address/logic/parser/ParserUtil.class
new file mode 100644
index 00000000000..7cd6bdedce4
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/ParserUtil.class differ
diff --git a/bin/main/seedu/address/logic/parser/Prefix.class b/bin/main/seedu/address/logic/parser/Prefix.class
new file mode 100644
index 00000000000..83fdbc507e8
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/Prefix.class differ
diff --git a/bin/main/seedu/address/logic/parser/ViewCommandParser.class b/bin/main/seedu/address/logic/parser/ViewCommandParser.class
new file mode 100644
index 00000000000..e80d85f07aa
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/ViewCommandParser.class differ
diff --git a/bin/main/seedu/address/logic/parser/exceptions/ParseException.class b/bin/main/seedu/address/logic/parser/exceptions/ParseException.class
new file mode 100644
index 00000000000..9f016040621
Binary files /dev/null and b/bin/main/seedu/address/logic/parser/exceptions/ParseException.class differ
diff --git a/bin/main/seedu/address/model/AddressBook.class b/bin/main/seedu/address/model/AddressBook.class
new file mode 100644
index 00000000000..7b81ad3ee86
Binary files /dev/null and b/bin/main/seedu/address/model/AddressBook.class differ
diff --git a/bin/main/seedu/address/model/Model.class b/bin/main/seedu/address/model/Model.class
new file mode 100644
index 00000000000..d663aa468ca
Binary files /dev/null and b/bin/main/seedu/address/model/Model.class differ
diff --git a/bin/main/seedu/address/model/ModelManager.class b/bin/main/seedu/address/model/ModelManager.class
new file mode 100644
index 00000000000..6138f17b9c6
Binary files /dev/null and b/bin/main/seedu/address/model/ModelManager.class differ
diff --git a/bin/main/seedu/address/model/ReadOnlyAddressBook.class b/bin/main/seedu/address/model/ReadOnlyAddressBook.class
new file mode 100644
index 00000000000..b5e5d6a37c5
Binary files /dev/null and b/bin/main/seedu/address/model/ReadOnlyAddressBook.class differ
diff --git a/bin/main/seedu/address/model/ReadOnlyUserPrefs.class b/bin/main/seedu/address/model/ReadOnlyUserPrefs.class
new file mode 100644
index 00000000000..b0b0f1bdaed
Binary files /dev/null and b/bin/main/seedu/address/model/ReadOnlyUserPrefs.class differ
diff --git a/bin/main/seedu/address/model/UserPrefs.class b/bin/main/seedu/address/model/UserPrefs.class
new file mode 100644
index 00000000000..60743a54418
Binary files /dev/null and b/bin/main/seedu/address/model/UserPrefs.class differ
diff --git a/bin/main/seedu/address/model/person/Address.class b/bin/main/seedu/address/model/person/Address.class
new file mode 100644
index 00000000000..f00fcc42970
Binary files /dev/null and b/bin/main/seedu/address/model/person/Address.class differ
diff --git a/bin/main/seedu/address/model/person/DateOfJoining.class b/bin/main/seedu/address/model/person/DateOfJoining.class
new file mode 100644
index 00000000000..0aed8ee4f49
Binary files /dev/null and b/bin/main/seedu/address/model/person/DateOfJoining.class differ
diff --git a/bin/main/seedu/address/model/person/DepartmentContainsKeywordPredicate.class b/bin/main/seedu/address/model/person/DepartmentContainsKeywordPredicate.class
new file mode 100644
index 00000000000..b8634dffd75
Binary files /dev/null and b/bin/main/seedu/address/model/person/DepartmentContainsKeywordPredicate.class differ
diff --git a/bin/main/seedu/address/model/person/Dob.class b/bin/main/seedu/address/model/person/Dob.class
new file mode 100644
index 00000000000..d719c9ec3a8
Binary files /dev/null and b/bin/main/seedu/address/model/person/Dob.class differ
diff --git a/bin/main/seedu/address/model/person/Email.class b/bin/main/seedu/address/model/person/Email.class
new file mode 100644
index 00000000000..bd0dc54ec2e
Binary files /dev/null and b/bin/main/seedu/address/model/person/Email.class differ
diff --git a/bin/main/seedu/address/model/person/EmploymentTypeContainsKeywordPredicate.class b/bin/main/seedu/address/model/person/EmploymentTypeContainsKeywordPredicate.class
new file mode 100644
index 00000000000..96d4c775799
Binary files /dev/null and b/bin/main/seedu/address/model/person/EmploymentTypeContainsKeywordPredicate.class differ
diff --git a/bin/main/seedu/address/model/person/Gender.class b/bin/main/seedu/address/model/person/Gender.class
new file mode 100644
index 00000000000..3085a603034
Binary files /dev/null and b/bin/main/seedu/address/model/person/Gender.class differ
diff --git a/bin/main/seedu/address/model/person/JobTitleContainsKeywordPredicate.class b/bin/main/seedu/address/model/person/JobTitleContainsKeywordPredicate.class
new file mode 100644
index 00000000000..21595ef62e9
Binary files /dev/null and b/bin/main/seedu/address/model/person/JobTitleContainsKeywordPredicate.class differ
diff --git a/bin/main/seedu/address/model/person/Name.class b/bin/main/seedu/address/model/person/Name.class
new file mode 100644
index 00000000000..b322f2d87e1
Binary files /dev/null and b/bin/main/seedu/address/model/person/Name.class differ
diff --git a/bin/main/seedu/address/model/person/NameContainsKeywordsPredicate.class b/bin/main/seedu/address/model/person/NameContainsKeywordsPredicate.class
new file mode 100644
index 00000000000..a427b82776c
Binary files /dev/null and b/bin/main/seedu/address/model/person/NameContainsKeywordsPredicate.class differ
diff --git a/bin/main/seedu/address/model/person/Nationality.class b/bin/main/seedu/address/model/person/Nationality.class
new file mode 100644
index 00000000000..6ad26686fe1
Binary files /dev/null and b/bin/main/seedu/address/model/person/Nationality.class differ
diff --git a/bin/main/seedu/address/model/person/Note.class b/bin/main/seedu/address/model/person/Note.class
new file mode 100644
index 00000000000..e955a737633
Binary files /dev/null and b/bin/main/seedu/address/model/person/Note.class differ
diff --git a/bin/main/seedu/address/model/person/Nric.class b/bin/main/seedu/address/model/person/Nric.class
new file mode 100644
index 00000000000..68ef0158567
Binary files /dev/null and b/bin/main/seedu/address/model/person/Nric.class differ
diff --git a/bin/main/seedu/address/model/person/Person.class b/bin/main/seedu/address/model/person/Person.class
new file mode 100644
index 00000000000..7912d6fc3c1
Binary files /dev/null and b/bin/main/seedu/address/model/person/Person.class differ
diff --git a/bin/main/seedu/address/model/person/Phone.class b/bin/main/seedu/address/model/person/Phone.class
new file mode 100644
index 00000000000..2662e11ae4b
Binary files /dev/null and b/bin/main/seedu/address/model/person/Phone.class differ
diff --git a/bin/main/seedu/address/model/person/ProfileContainsKeywordsPredicate.class b/bin/main/seedu/address/model/person/ProfileContainsKeywordsPredicate.class
new file mode 100644
index 00000000000..44828b34199
Binary files /dev/null and b/bin/main/seedu/address/model/person/ProfileContainsKeywordsPredicate.class differ
diff --git a/bin/main/seedu/address/model/person/UniquePersonList.class b/bin/main/seedu/address/model/person/UniquePersonList.class
new file mode 100644
index 00000000000..557f2d864b4
Binary files /dev/null and b/bin/main/seedu/address/model/person/UniquePersonList.class differ
diff --git a/bin/main/seedu/address/model/person/exceptions/DuplicatePersonException.class b/bin/main/seedu/address/model/person/exceptions/DuplicatePersonException.class
new file mode 100644
index 00000000000..156b44b7d17
Binary files /dev/null and b/bin/main/seedu/address/model/person/exceptions/DuplicatePersonException.class differ
diff --git a/bin/main/seedu/address/model/person/exceptions/PersonNotFoundException.class b/bin/main/seedu/address/model/person/exceptions/PersonNotFoundException.class
new file mode 100644
index 00000000000..75a1a0ee817
Binary files /dev/null and b/bin/main/seedu/address/model/person/exceptions/PersonNotFoundException.class differ
diff --git a/bin/main/seedu/address/model/tag/Department.class b/bin/main/seedu/address/model/tag/Department.class
new file mode 100644
index 00000000000..ab331b1cf99
Binary files /dev/null and b/bin/main/seedu/address/model/tag/Department.class differ
diff --git a/bin/main/seedu/address/model/tag/EmploymentType.class b/bin/main/seedu/address/model/tag/EmploymentType.class
new file mode 100644
index 00000000000..56477cacb59
Binary files /dev/null and b/bin/main/seedu/address/model/tag/EmploymentType.class differ
diff --git a/bin/main/seedu/address/model/tag/JobTitle.class b/bin/main/seedu/address/model/tag/JobTitle.class
new file mode 100644
index 00000000000..d534d900b13
Binary files /dev/null and b/bin/main/seedu/address/model/tag/JobTitle.class differ
diff --git a/bin/main/seedu/address/model/tag/Tag.class b/bin/main/seedu/address/model/tag/Tag.class
new file mode 100644
index 00000000000..c34a4af8e0a
Binary files /dev/null and b/bin/main/seedu/address/model/tag/Tag.class differ
diff --git a/bin/main/seedu/address/model/util/SampleDataUtil.class b/bin/main/seedu/address/model/util/SampleDataUtil.class
new file mode 100644
index 00000000000..9dcb6545813
Binary files /dev/null and b/bin/main/seedu/address/model/util/SampleDataUtil.class differ
diff --git a/bin/main/seedu/address/storage/AddressBookStorage.class b/bin/main/seedu/address/storage/AddressBookStorage.class
new file mode 100644
index 00000000000..a530bb16c9e
Binary files /dev/null and b/bin/main/seedu/address/storage/AddressBookStorage.class differ
diff --git a/bin/main/seedu/address/storage/JsonAdaptedPerson.class b/bin/main/seedu/address/storage/JsonAdaptedPerson.class
new file mode 100644
index 00000000000..50b2d46554f
Binary files /dev/null and b/bin/main/seedu/address/storage/JsonAdaptedPerson.class differ
diff --git a/bin/main/seedu/address/storage/JsonAdaptedTag.class b/bin/main/seedu/address/storage/JsonAdaptedTag.class
new file mode 100644
index 00000000000..79fc304f44f
Binary files /dev/null and b/bin/main/seedu/address/storage/JsonAdaptedTag.class differ
diff --git a/bin/main/seedu/address/storage/JsonAddressBookStorage.class b/bin/main/seedu/address/storage/JsonAddressBookStorage.class
new file mode 100644
index 00000000000..d2610e5a90d
Binary files /dev/null and b/bin/main/seedu/address/storage/JsonAddressBookStorage.class differ
diff --git a/bin/main/seedu/address/storage/JsonSerializableAddressBook.class b/bin/main/seedu/address/storage/JsonSerializableAddressBook.class
new file mode 100644
index 00000000000..9fcfe5e9a1b
Binary files /dev/null and b/bin/main/seedu/address/storage/JsonSerializableAddressBook.class differ
diff --git a/bin/main/seedu/address/storage/JsonUserPrefsStorage.class b/bin/main/seedu/address/storage/JsonUserPrefsStorage.class
new file mode 100644
index 00000000000..bd0d06847a0
Binary files /dev/null and b/bin/main/seedu/address/storage/JsonUserPrefsStorage.class differ
diff --git a/bin/main/seedu/address/storage/Storage.class b/bin/main/seedu/address/storage/Storage.class
new file mode 100644
index 00000000000..c48a2adfabd
Binary files /dev/null and b/bin/main/seedu/address/storage/Storage.class differ
diff --git a/bin/main/seedu/address/storage/StorageManager.class b/bin/main/seedu/address/storage/StorageManager.class
new file mode 100644
index 00000000000..98652728013
Binary files /dev/null and b/bin/main/seedu/address/storage/StorageManager.class differ
diff --git a/bin/main/seedu/address/storage/UserPrefsStorage.class b/bin/main/seedu/address/storage/UserPrefsStorage.class
new file mode 100644
index 00000000000..4a3de2de21f
Binary files /dev/null and b/bin/main/seedu/address/storage/UserPrefsStorage.class differ
diff --git a/bin/main/seedu/address/ui/CommandBox$CommandExecutor.class b/bin/main/seedu/address/ui/CommandBox$CommandExecutor.class
new file mode 100644
index 00000000000..46c12f4748d
Binary files /dev/null and b/bin/main/seedu/address/ui/CommandBox$CommandExecutor.class differ
diff --git a/bin/main/seedu/address/ui/CommandBox.class b/bin/main/seedu/address/ui/CommandBox.class
new file mode 100644
index 00000000000..59b88853abc
Binary files /dev/null and b/bin/main/seedu/address/ui/CommandBox.class differ
diff --git a/bin/main/seedu/address/ui/HelpWindow.class b/bin/main/seedu/address/ui/HelpWindow.class
new file mode 100644
index 00000000000..b64e971a239
Binary files /dev/null and b/bin/main/seedu/address/ui/HelpWindow.class differ
diff --git a/bin/main/seedu/address/ui/HomePersonCard.class b/bin/main/seedu/address/ui/HomePersonCard.class
new file mode 100644
index 00000000000..25e118e0222
Binary files /dev/null and b/bin/main/seedu/address/ui/HomePersonCard.class differ
diff --git a/bin/main/seedu/address/ui/HomePersonCardPanel$PersonListViewCell.class b/bin/main/seedu/address/ui/HomePersonCardPanel$PersonListViewCell.class
new file mode 100644
index 00000000000..5a6600eb4e7
Binary files /dev/null and b/bin/main/seedu/address/ui/HomePersonCardPanel$PersonListViewCell.class differ
diff --git a/bin/main/seedu/address/ui/HomePersonCardPanel.class b/bin/main/seedu/address/ui/HomePersonCardPanel.class
new file mode 100644
index 00000000000..997c99c84fb
Binary files /dev/null and b/bin/main/seedu/address/ui/HomePersonCardPanel.class differ
diff --git a/bin/main/seedu/address/ui/MainWindow.class b/bin/main/seedu/address/ui/MainWindow.class
new file mode 100644
index 00000000000..9f46d41380e
Binary files /dev/null and b/bin/main/seedu/address/ui/MainWindow.class differ
diff --git a/bin/main/seedu/address/ui/PersonCard.class b/bin/main/seedu/address/ui/PersonCard.class
new file mode 100644
index 00000000000..435f4e34ea1
Binary files /dev/null and b/bin/main/seedu/address/ui/PersonCard.class differ
diff --git a/bin/main/seedu/address/ui/PersonListPanel$PersonListViewCell.class b/bin/main/seedu/address/ui/PersonListPanel$PersonListViewCell.class
new file mode 100644
index 00000000000..7eeb1b8e977
Binary files /dev/null and b/bin/main/seedu/address/ui/PersonListPanel$PersonListViewCell.class differ
diff --git a/bin/main/seedu/address/ui/PersonListPanel.class b/bin/main/seedu/address/ui/PersonListPanel.class
new file mode 100644
index 00000000000..5cbe473e74c
Binary files /dev/null and b/bin/main/seedu/address/ui/PersonListPanel.class differ
diff --git a/bin/main/seedu/address/ui/PersonNoteCard.class b/bin/main/seedu/address/ui/PersonNoteCard.class
new file mode 100644
index 00000000000..a8cb4d47db7
Binary files /dev/null and b/bin/main/seedu/address/ui/PersonNoteCard.class differ
diff --git a/bin/main/seedu/address/ui/PersonNoteListPanel$PersonNoteListViewCell.class b/bin/main/seedu/address/ui/PersonNoteListPanel$PersonNoteListViewCell.class
new file mode 100644
index 00000000000..dc9cc4ac126
Binary files /dev/null and b/bin/main/seedu/address/ui/PersonNoteListPanel$PersonNoteListViewCell.class differ
diff --git a/bin/main/seedu/address/ui/PersonNoteListPanel.class b/bin/main/seedu/address/ui/PersonNoteListPanel.class
new file mode 100644
index 00000000000..5e1d154aceb
Binary files /dev/null and b/bin/main/seedu/address/ui/PersonNoteListPanel.class differ
diff --git a/bin/main/seedu/address/ui/ResultDisplay.class b/bin/main/seedu/address/ui/ResultDisplay.class
new file mode 100644
index 00000000000..6ef7ea561fc
Binary files /dev/null and b/bin/main/seedu/address/ui/ResultDisplay.class differ
diff --git a/bin/main/seedu/address/ui/StatusBarFooter.class b/bin/main/seedu/address/ui/StatusBarFooter.class
new file mode 100644
index 00000000000..82fae56488a
Binary files /dev/null and b/bin/main/seedu/address/ui/StatusBarFooter.class differ
diff --git a/bin/main/seedu/address/ui/Ui.class b/bin/main/seedu/address/ui/Ui.class
new file mode 100644
index 00000000000..0be5b266f15
Binary files /dev/null and b/bin/main/seedu/address/ui/Ui.class differ
diff --git a/bin/main/seedu/address/ui/UiManager.class b/bin/main/seedu/address/ui/UiManager.class
new file mode 100644
index 00000000000..ee392cddbb3
Binary files /dev/null and b/bin/main/seedu/address/ui/UiManager.class differ
diff --git a/bin/main/seedu/address/ui/UiPart.class b/bin/main/seedu/address/ui/UiPart.class
new file mode 100644
index 00000000000..94117a2e79d
Binary files /dev/null and b/bin/main/seedu/address/ui/UiPart.class differ
diff --git a/bin/main/view/CommandBox.fxml b/bin/main/view/CommandBox.fxml
new file mode 100644
index 00000000000..124283a392e
--- /dev/null
+++ b/bin/main/view/CommandBox.fxml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/DarkTheme.css b/bin/main/view/DarkTheme.css
new file mode 100644
index 00000000000..85b95ff669e
--- /dev/null
+++ b/bin/main/view/DarkTheme.css
@@ -0,0 +1,398 @@
+.background {
+ -fx-background-color: derive(#1d1d1d, 20%);
+ background-color: #383838; /* Used in the default.html file */
+}
+
+.label {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: #555555;
+ -fx-opacity: 0.9;
+}
+
+.label-bright {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: white;
+ -fx-opacity: 1;
+}
+
+.label-header {
+ -fx-font-size: 32pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-opacity: 1;
+}
+
+.text-field {
+ -fx-font-size: 12pt;
+ -fx-font-family: "Segoe UI Semibold";
+}
+
+.tab-pane {
+ -fx-padding: 0 0 0 1;
+}
+
+.tab-pane .tab-header-area {
+ -fx-padding: 0 0 0 0;
+ -fx-min-height: 0;
+ -fx-max-height: 0;
+}
+
+.table-view {
+ -fx-base: #1d1d1d;
+ -fx-control-inner-background: #1d1d1d;
+ -fx-background-color: #1d1d1d;
+ -fx-table-cell-border-color: transparent;
+ -fx-table-header-border-color: transparent;
+ -fx-padding: 5;
+}
+
+.table-view .column-header-background {
+ -fx-background-color: transparent;
+}
+
+.table-view .column-header, .table-view .filler {
+ -fx-size: 35;
+ -fx-border-width: 0 0 1 0;
+ -fx-background-color: transparent;
+ -fx-border-color:
+ transparent
+ transparent
+ derive(-fx-base, 80%)
+ transparent;
+ -fx-border-insets: 0 10 1 0;
+}
+
+.table-view .column-header .label {
+ -fx-font-size: 20pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-alignment: center-left;
+ -fx-opacity: 1;
+}
+
+.table-view:focused .table-row-cell:filled:focused:selected {
+ -fx-background-color: -fx-focus-color;
+}
+
+.split-pane:horizontal .split-pane-divider {
+ -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-border-color: transparent transparent transparent #4d4d4d;
+}
+
+.split-pane {
+ -fx-border-radius: 1;
+ -fx-border-width: 1;
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.list-view {
+ -fx-background-insets: 0;
+ -fx-padding: 0;
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.list-cell {
+ -fx-label-padding: 0 0 0 0;
+ -fx-graphic-text-gap : 0;
+ -fx-padding: 0 0 0 0;
+}
+
+.list-cell:filled:even {
+ -fx-background-color: #3c3e3f;
+}
+
+.list-cell:filled:odd {
+ -fx-background-color: #515658;
+}
+
+.list-cell:filled:selected {
+ -fx-background-color: #424d5f;
+}
+
+.list-cell:filled:selected #cardPane {
+ -fx-border-color: #3e7b91;
+ -fx-border-width: 1;
+}
+
+.list-cell .label {
+ -fx-text-fill: white;
+}
+
+.cell_big_label {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 17px;
+ -fx-text-fill: #010504;
+ -fx-padding: 2;
+}
+
+.cell_big_home_label {
+ -fx-font-family: "Segoe UI Light";
+ -fx-font-size: 23px;
+ -fx-text-fill: #010504;
+ -fx-padding: 2;
+}
+
+.cell_home_label {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 16px;
+ -fx-text-fill: #010504;
+}
+
+.cell_small_label {
+ -fx-font-family: "Segoe UI";
+ -fx-font-size: 13px;
+ -fx-text-fill: #010504;
+}
+
+.stack-pane {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.pane-with-border {
+ -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-border-color: derive(#1d1d1d, 10%);
+ -fx-border-top-width: 1px;
+}
+
+.status-bar {
+ -fx-background-color: derive(#1d1d1d, 30%);
+}
+
+.result-display {
+ -fx-background-color: transparent;
+ -fx-font-family: "Segoe UI Light";
+ -fx-font-size: 13pt;
+ -fx-text-fill: white;
+}
+
+.result-display .label {
+ -fx-text-fill: black !important;
+}
+
+.status-bar .label {
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-padding: 4px;
+ -fx-pref-height: 30px;
+}
+
+.status-bar-with-border {
+ -fx-background-color: derive(#1d1d1d, 30%);
+ -fx-border-color: derive(#1d1d1d, 25%);
+ -fx-border-width: 1px;
+}
+
+.status-bar-with-border .label {
+ -fx-text-fill: white;
+}
+
+.grid-pane {
+ -fx-background-color: derive(#1d1d1d, 30%);
+ -fx-border-color: derive(#1d1d1d, 30%);
+ -fx-border-width: 1px;
+}
+
+.grid-pane .stack-pane {
+ -fx-background-color: derive(#1d1d1d, 30%);
+}
+
+.context-menu {
+ -fx-background-color: derive(#1d1d1d, 50%);
+}
+
+.context-menu .label {
+ -fx-text-fill: white;
+}
+
+.menu-bar {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.menu-bar .label {
+ -fx-font-size: 14pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-opacity: 0.9;
+}
+
+.menu .left-container {
+ -fx-background-color: black;
+}
+
+/*
+ * Metro style Push Button
+ * Author: Pedro Duque Vieira
+ * http://pixelduke.wordpress.com/2012/10/23/jmetro-windows-8-controls-on-java/
+ */
+.button {
+ -fx-padding: 5 22 5 22;
+ -fx-border-color: #e2e2e2;
+ -fx-border-width: 2;
+ -fx-background-radius: 0;
+ -fx-background-color: #1d1d1d;
+ -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif;
+ -fx-font-size: 11pt;
+ -fx-text-fill: #d8d8d8;
+ -fx-background-insets: 0 0 0 0, 0, 1, 2;
+}
+
+.button:hover {
+ -fx-background-color: #3a3a3a;
+}
+
+.button:pressed, .button:default:hover:pressed {
+ -fx-background-color: white;
+ -fx-text-fill: #1d1d1d;
+}
+
+.button:focused {
+ -fx-border-color: white, white;
+ -fx-border-width: 1, 1;
+ -fx-border-style: solid, segments(1, 1);
+ -fx-border-radius: 0, 0;
+ -fx-border-insets: 1 1 1 1, 0;
+}
+
+.button:disabled, .button:default:disabled {
+ -fx-opacity: 0.4;
+ -fx-background-color: #1d1d1d;
+ -fx-text-fill: white;
+}
+
+.button:default {
+ -fx-background-color: -fx-focus-color;
+ -fx-text-fill: #ffffff;
+}
+
+.button:default:hover {
+ -fx-background-color: derive(-fx-focus-color, 30%);
+}
+
+.dialog-pane {
+ -fx-background-color: #1d1d1d;
+}
+
+.dialog-pane > *.button-bar > *.container {
+ -fx-background-color: #1d1d1d;
+}
+
+.dialog-pane > *.label.content {
+ -fx-font-size: 14px;
+ -fx-font-weight: bold;
+ -fx-text-fill: white;
+}
+
+.dialog-pane:header *.header-panel {
+ -fx-background-color: derive(#1d1d1d, 25%);
+}
+
+.dialog-pane:header *.header-panel *.label {
+ -fx-font-size: 18px;
+ -fx-font-style: italic;
+ -fx-fill: white;
+ -fx-text-fill: white;
+}
+
+.scroll-bar {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.scroll-bar .thumb {
+ -fx-background-color: derive(#1d1d1d, 50%);
+ -fx-background-insets: 3;
+}
+
+.scroll-bar .increment-button, .scroll-bar .decrement-button {
+ -fx-background-color: transparent;
+ -fx-padding: 0 0 0 0;
+}
+
+.scroll-bar .increment-arrow, .scroll-bar .decrement-arrow {
+ -fx-shape: " ";
+}
+
+.scroll-bar:vertical .increment-arrow, .scroll-bar:vertical .decrement-arrow {
+ -fx-padding: 1 8 1 8;
+}
+
+.scroll-bar:horizontal .increment-arrow, .scroll-bar:horizontal .decrement-arrow {
+ -fx-padding: 8 1 8 1;
+}
+
+#cardPane {
+ -fx-background-color: transparent;
+ -fx-border-width: 0;
+}
+
+#commandTypeLabel {
+ -fx-font-size: 11px;
+ -fx-text-fill: #F70D1A;
+}
+
+#commandTextField {
+ -fx-background-color: transparent #383838 transparent #383838;
+ -fx-background-insets: 0;
+ -fx-border-color: #383838 #383838 #ffffff #383838;
+ -fx-border-insets: 0;
+ -fx-border-width: 1;
+ -fx-font-family: "Segoe UI Light";
+ -fx-font-size: 13pt;
+ -fx-text-fill: white;
+}
+
+#filterField, #personListPanel, #personWebpage {
+ -fx-effect: innershadow(gaussian, black, 10, 0, 0, 0);
+}
+
+#resultDisplay .content {
+ -fx-background-color: transparent, #383838, transparent, #383838;
+ -fx-background-radius: 0;
+}
+
+#tagBox {
+ -fx-alignment: center-left;
+}
+
+#department {
+ -fx-hgap: 15;
+ -fx-vgap: 10;
+}
+
+#department .label {
+ -fx-text-fill: white;
+ -fx-background-color: #73acd5;
+ -fx-padding: 1 3 1 3;
+ -fx-border-radius: 2;
+ -fx-background-radius: 2;
+ -fx-font-size: 13;
+}
+
+#employmentType {
+ -fx-hgap: 15;
+ -fx-vgap: 10;
+}
+
+#employmentType .label {
+ -fx-text-fill: white;
+ -fx-background-color: #467cd6;
+ -fx-padding: 1 3 1 3;
+ -fx-border-radius: 2;
+ -fx-background-radius: 2;
+ -fx-font-size: 13;
+}
+
+#jobTitle {
+ -fx-hgap: 15;
+ -fx-vgap: 10;
+}
+
+#jobTitle .label {
+ -fx-text-fill: white;
+ -fx-background-color: #8f8d8d;
+ -fx-padding: 1 3 1 3;
+ -fx-border-radius: 2;
+ -fx-background-radius: 2;
+ -fx-font-size: 13;
+}
diff --git a/bin/main/view/Extensions.css b/bin/main/view/Extensions.css
new file mode 100644
index 00000000000..bfe82a85964
--- /dev/null
+++ b/bin/main/view/Extensions.css
@@ -0,0 +1,20 @@
+
+.error {
+ -fx-text-fill: #d06651 !important; /* The error class should always override the default text-fill style */
+}
+
+.list-cell:empty {
+ /* Empty cells will not have alternating colours */
+ -fx-background: #383838;
+}
+
+.tag-selector {
+ -fx-border-width: 1;
+ -fx-border-color: white;
+ -fx-border-radius: 3;
+ -fx-background-radius: 3;
+}
+
+.tooltip-text {
+ -fx-text-fill: white;
+}
diff --git a/bin/main/view/HelpWindow.css b/bin/main/view/HelpWindow.css
new file mode 100644
index 00000000000..17e8a8722cd
--- /dev/null
+++ b/bin/main/view/HelpWindow.css
@@ -0,0 +1,19 @@
+#copyButton, #helpMessage {
+ -fx-text-fill: white;
+}
+
+#copyButton {
+ -fx-background-color: dimgray;
+}
+
+#copyButton:hover {
+ -fx-background-color: gray;
+}
+
+#copyButton:armed {
+ -fx-background-color: darkgray;
+}
+
+#helpMessageContainer {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
diff --git a/bin/main/view/HelpWindow.fxml b/bin/main/view/HelpWindow.fxml
new file mode 100644
index 00000000000..e01f330de33
--- /dev/null
+++ b/bin/main/view/HelpWindow.fxml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/HomePersonCard.fxml b/bin/main/view/HomePersonCard.fxml
new file mode 100644
index 00000000000..cf37e851682
--- /dev/null
+++ b/bin/main/view/HomePersonCard.fxml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/HomePersonCardPanel.fxml b/bin/main/view/HomePersonCardPanel.fxml
new file mode 100644
index 00000000000..181ce27cae0
--- /dev/null
+++ b/bin/main/view/HomePersonCardPanel.fxml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/MainWindow.fxml b/bin/main/view/MainWindow.fxml
new file mode 100644
index 00000000000..0c1e97d82a5
--- /dev/null
+++ b/bin/main/view/MainWindow.fxml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/PersonListCard.fxml b/bin/main/view/PersonListCard.fxml
new file mode 100644
index 00000000000..0a81c8e7b72
--- /dev/null
+++ b/bin/main/view/PersonListCard.fxml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/PersonListPanel.fxml b/bin/main/view/PersonListPanel.fxml
new file mode 100644
index 00000000000..a1bb6bbace8
--- /dev/null
+++ b/bin/main/view/PersonListPanel.fxml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/PersonNoteCard.fxml b/bin/main/view/PersonNoteCard.fxml
new file mode 100644
index 00000000000..36235a8d4c2
--- /dev/null
+++ b/bin/main/view/PersonNoteCard.fxml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/PersonNoteListPanel.fxml b/bin/main/view/PersonNoteListPanel.fxml
new file mode 100644
index 00000000000..ddf1525e1b5
--- /dev/null
+++ b/bin/main/view/PersonNoteListPanel.fxml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/ResultDisplay.fxml b/bin/main/view/ResultDisplay.fxml
new file mode 100644
index 00000000000..01b691792a9
--- /dev/null
+++ b/bin/main/view/ResultDisplay.fxml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
diff --git a/bin/main/view/StatusBarFooter.fxml b/bin/main/view/StatusBarFooter.fxml
new file mode 100644
index 00000000000..7b430f9c6a2
--- /dev/null
+++ b/bin/main/view/StatusBarFooter.fxml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/test/seedu/address/AppParametersTest$ParametersStub.class b/bin/test/seedu/address/AppParametersTest$ParametersStub.class
new file mode 100644
index 00000000000..3c3efc5dc50
Binary files /dev/null and b/bin/test/seedu/address/AppParametersTest$ParametersStub.class differ
diff --git a/bin/test/seedu/address/AppParametersTest.class b/bin/test/seedu/address/AppParametersTest.class
new file mode 100644
index 00000000000..c4b0b840f09
Binary files /dev/null and b/bin/test/seedu/address/AppParametersTest.class differ
diff --git a/bin/test/seedu/address/commons/core/ConfigTest.class b/bin/test/seedu/address/commons/core/ConfigTest.class
new file mode 100644
index 00000000000..369aa5022c0
Binary files /dev/null and b/bin/test/seedu/address/commons/core/ConfigTest.class differ
diff --git a/bin/test/seedu/address/commons/core/GuiSettingsTest.class b/bin/test/seedu/address/commons/core/GuiSettingsTest.class
new file mode 100644
index 00000000000..b245a7ea1dc
Binary files /dev/null and b/bin/test/seedu/address/commons/core/GuiSettingsTest.class differ
diff --git a/bin/test/seedu/address/commons/core/VersionTest.class b/bin/test/seedu/address/commons/core/VersionTest.class
new file mode 100644
index 00000000000..bf494a62d77
Binary files /dev/null and b/bin/test/seedu/address/commons/core/VersionTest.class differ
diff --git a/bin/test/seedu/address/commons/core/index/IndexTest.class b/bin/test/seedu/address/commons/core/index/IndexTest.class
new file mode 100644
index 00000000000..8883a7928ad
Binary files /dev/null and b/bin/test/seedu/address/commons/core/index/IndexTest.class differ
diff --git a/bin/test/seedu/address/commons/util/AppUtilTest.class b/bin/test/seedu/address/commons/util/AppUtilTest.class
new file mode 100644
index 00000000000..66f0951b3b9
Binary files /dev/null and b/bin/test/seedu/address/commons/util/AppUtilTest.class differ
diff --git a/bin/test/seedu/address/commons/util/CollectionUtilTest.class b/bin/test/seedu/address/commons/util/CollectionUtilTest.class
new file mode 100644
index 00000000000..7ad212710d7
Binary files /dev/null and b/bin/test/seedu/address/commons/util/CollectionUtilTest.class differ
diff --git a/bin/test/seedu/address/commons/util/ConfigUtilTest.class b/bin/test/seedu/address/commons/util/ConfigUtilTest.class
new file mode 100644
index 00000000000..575a0c81011
Binary files /dev/null and b/bin/test/seedu/address/commons/util/ConfigUtilTest.class differ
diff --git a/bin/test/seedu/address/commons/util/FileUtilTest.class b/bin/test/seedu/address/commons/util/FileUtilTest.class
new file mode 100644
index 00000000000..3867fc132a7
Binary files /dev/null and b/bin/test/seedu/address/commons/util/FileUtilTest.class differ
diff --git a/bin/test/seedu/address/commons/util/JsonUtilTest.class b/bin/test/seedu/address/commons/util/JsonUtilTest.class
new file mode 100644
index 00000000000..6c515f52608
Binary files /dev/null and b/bin/test/seedu/address/commons/util/JsonUtilTest.class differ
diff --git a/bin/test/seedu/address/commons/util/StringUtilTest.class b/bin/test/seedu/address/commons/util/StringUtilTest.class
new file mode 100644
index 00000000000..9ca6dc087d8
Binary files /dev/null and b/bin/test/seedu/address/commons/util/StringUtilTest.class differ
diff --git a/bin/test/seedu/address/logic/LogicManagerTest$1.class b/bin/test/seedu/address/logic/LogicManagerTest$1.class
new file mode 100644
index 00000000000..0b3aea40b25
Binary files /dev/null and b/bin/test/seedu/address/logic/LogicManagerTest$1.class differ
diff --git a/bin/test/seedu/address/logic/LogicManagerTest.class b/bin/test/seedu/address/logic/LogicManagerTest.class
new file mode 100644
index 00000000000..e7b9168a136
Binary files /dev/null and b/bin/test/seedu/address/logic/LogicManagerTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/AddCommandIntegrationTest.class b/bin/test/seedu/address/logic/commands/AddCommandIntegrationTest.class
new file mode 100644
index 00000000000..7571b023daf
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/AddCommandIntegrationTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStub.class b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStub.class
new file mode 100644
index 00000000000..e6c60ec0e45
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStub.class differ
diff --git a/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubAcceptingPersonAdded.class b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubAcceptingPersonAdded.class
new file mode 100644
index 00000000000..31eb59c9446
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubAcceptingPersonAdded.class differ
diff --git a/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubWithPerson.class b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubWithPerson.class
new file mode 100644
index 00000000000..03525b76fe4
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/AddCommandTest$ModelStubWithPerson.class differ
diff --git a/bin/test/seedu/address/logic/commands/AddCommandTest.class b/bin/test/seedu/address/logic/commands/AddCommandTest.class
new file mode 100644
index 00000000000..c748d77fd4b
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/AddCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/ClearCommandTest.class b/bin/test/seedu/address/logic/commands/ClearCommandTest.class
new file mode 100644
index 00000000000..b16a04f723c
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/ClearCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/CommandResultTest.class b/bin/test/seedu/address/logic/commands/CommandResultTest.class
new file mode 100644
index 00000000000..5c94afb5211
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/CommandResultTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/CommandTestUtil.class b/bin/test/seedu/address/logic/commands/CommandTestUtil.class
new file mode 100644
index 00000000000..6339a988397
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/CommandTestUtil.class differ
diff --git a/bin/test/seedu/address/logic/commands/DeleteCommandTest.class b/bin/test/seedu/address/logic/commands/DeleteCommandTest.class
new file mode 100644
index 00000000000..f8220781d6c
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/DeleteCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/EditCommandTest.class b/bin/test/seedu/address/logic/commands/EditCommandTest.class
new file mode 100644
index 00000000000..a405c03a710
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/EditCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/EditPersonDescriptorTest.class b/bin/test/seedu/address/logic/commands/EditPersonDescriptorTest.class
new file mode 100644
index 00000000000..41891ed3c8f
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/EditPersonDescriptorTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/ExitCommandTest.class b/bin/test/seedu/address/logic/commands/ExitCommandTest.class
new file mode 100644
index 00000000000..7798f378515
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/ExitCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/FindByDepartmentCommandTest.class b/bin/test/seedu/address/logic/commands/FindByDepartmentCommandTest.class
new file mode 100644
index 00000000000..a16601e7ddc
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/FindByDepartmentCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/FindByEmploymentTypeCommandTest.class b/bin/test/seedu/address/logic/commands/FindByEmploymentTypeCommandTest.class
new file mode 100644
index 00000000000..00823c28746
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/FindByEmploymentTypeCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/FindByJobTitleCommandTest.class b/bin/test/seedu/address/logic/commands/FindByJobTitleCommandTest.class
new file mode 100644
index 00000000000..1e46e521999
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/FindByJobTitleCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/FindCommandTest.class b/bin/test/seedu/address/logic/commands/FindCommandTest.class
new file mode 100644
index 00000000000..2626929a350
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/FindCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/HelpCommandTest.class b/bin/test/seedu/address/logic/commands/HelpCommandTest.class
new file mode 100644
index 00000000000..05dfd86cf98
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/HelpCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/ListCommandTest.class b/bin/test/seedu/address/logic/commands/ListCommandTest.class
new file mode 100644
index 00000000000..d8e5ddfda89
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/ListCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/NoteCommandTest.class b/bin/test/seedu/address/logic/commands/NoteCommandTest.class
new file mode 100644
index 00000000000..39b767453b8
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/NoteCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/commands/ViewCommandTest.class b/bin/test/seedu/address/logic/commands/ViewCommandTest.class
new file mode 100644
index 00000000000..61e05c5a5d2
Binary files /dev/null and b/bin/test/seedu/address/logic/commands/ViewCommandTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/AddCommandParserTest.class b/bin/test/seedu/address/logic/parser/AddCommandParserTest.class
new file mode 100644
index 00000000000..1e8d9c1db69
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/AddCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/AddressBookParserTest.class b/bin/test/seedu/address/logic/parser/AddressBookParserTest.class
new file mode 100644
index 00000000000..8099248a495
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/AddressBookParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/ArgumentTokenizerTest.class b/bin/test/seedu/address/logic/parser/ArgumentTokenizerTest.class
new file mode 100644
index 00000000000..f174b22bcab
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/ArgumentTokenizerTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/CommandParserTestUtil.class b/bin/test/seedu/address/logic/parser/CommandParserTestUtil.class
new file mode 100644
index 00000000000..10b32228294
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/CommandParserTestUtil.class differ
diff --git a/bin/test/seedu/address/logic/parser/DeleteCommandParserTest.class b/bin/test/seedu/address/logic/parser/DeleteCommandParserTest.class
new file mode 100644
index 00000000000..1b8ab3f9128
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/DeleteCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/EditCommandParserTest.class b/bin/test/seedu/address/logic/parser/EditCommandParserTest.class
new file mode 100644
index 00000000000..bded5b2d87d
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/EditCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/FindByDepartmentCommandParserTest.class b/bin/test/seedu/address/logic/parser/FindByDepartmentCommandParserTest.class
new file mode 100644
index 00000000000..f73eea6f284
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/FindByDepartmentCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/FindByEmploymentTypeCommandParserTest.class b/bin/test/seedu/address/logic/parser/FindByEmploymentTypeCommandParserTest.class
new file mode 100644
index 00000000000..f94b61b27e5
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/FindByEmploymentTypeCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/FindByJobTitleCommandParserTest.class b/bin/test/seedu/address/logic/parser/FindByJobTitleCommandParserTest.class
new file mode 100644
index 00000000000..7f87e8fa065
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/FindByJobTitleCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/FindCommandParserTest.class b/bin/test/seedu/address/logic/parser/FindCommandParserTest.class
new file mode 100644
index 00000000000..e69d508e943
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/FindCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/NoteCommandParserTest.class b/bin/test/seedu/address/logic/parser/NoteCommandParserTest.class
new file mode 100644
index 00000000000..0e22fc09030
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/NoteCommandParserTest.class differ
diff --git a/bin/test/seedu/address/logic/parser/ParserUtilTest.class b/bin/test/seedu/address/logic/parser/ParserUtilTest.class
new file mode 100644
index 00000000000..41167683c8b
Binary files /dev/null and b/bin/test/seedu/address/logic/parser/ParserUtilTest.class differ
diff --git a/bin/test/seedu/address/model/AddressBookTest$AddressBookStub.class b/bin/test/seedu/address/model/AddressBookTest$AddressBookStub.class
new file mode 100644
index 00000000000..82ef0021df4
Binary files /dev/null and b/bin/test/seedu/address/model/AddressBookTest$AddressBookStub.class differ
diff --git a/bin/test/seedu/address/model/AddressBookTest.class b/bin/test/seedu/address/model/AddressBookTest.class
new file mode 100644
index 00000000000..5a5fbc455ed
Binary files /dev/null and b/bin/test/seedu/address/model/AddressBookTest.class differ
diff --git a/bin/test/seedu/address/model/ModelManagerTest.class b/bin/test/seedu/address/model/ModelManagerTest.class
new file mode 100644
index 00000000000..05d4e5d48da
Binary files /dev/null and b/bin/test/seedu/address/model/ModelManagerTest.class differ
diff --git a/bin/test/seedu/address/model/UserPrefsTest.class b/bin/test/seedu/address/model/UserPrefsTest.class
new file mode 100644
index 00000000000..a976838e182
Binary files /dev/null and b/bin/test/seedu/address/model/UserPrefsTest.class differ
diff --git a/bin/test/seedu/address/model/person/AddressTest.class b/bin/test/seedu/address/model/person/AddressTest.class
new file mode 100644
index 00000000000..e249ed28d73
Binary files /dev/null and b/bin/test/seedu/address/model/person/AddressTest.class differ
diff --git a/bin/test/seedu/address/model/person/DateOfJoiningTest.class b/bin/test/seedu/address/model/person/DateOfJoiningTest.class
new file mode 100644
index 00000000000..47d1304520f
Binary files /dev/null and b/bin/test/seedu/address/model/person/DateOfJoiningTest.class differ
diff --git a/bin/test/seedu/address/model/person/DobTest.class b/bin/test/seedu/address/model/person/DobTest.class
new file mode 100644
index 00000000000..11b243b828e
Binary files /dev/null and b/bin/test/seedu/address/model/person/DobTest.class differ
diff --git a/bin/test/seedu/address/model/person/EmailTest.class b/bin/test/seedu/address/model/person/EmailTest.class
new file mode 100644
index 00000000000..95b530a9e96
Binary files /dev/null and b/bin/test/seedu/address/model/person/EmailTest.class differ
diff --git a/bin/test/seedu/address/model/person/GenderTest.class b/bin/test/seedu/address/model/person/GenderTest.class
new file mode 100644
index 00000000000..28151bf7d02
Binary files /dev/null and b/bin/test/seedu/address/model/person/GenderTest.class differ
diff --git a/bin/test/seedu/address/model/person/NameContainsKeywordsPredicateTest.class b/bin/test/seedu/address/model/person/NameContainsKeywordsPredicateTest.class
new file mode 100644
index 00000000000..abf9413340f
Binary files /dev/null and b/bin/test/seedu/address/model/person/NameContainsKeywordsPredicateTest.class differ
diff --git a/bin/test/seedu/address/model/person/NameTest.class b/bin/test/seedu/address/model/person/NameTest.class
new file mode 100644
index 00000000000..14cae88f580
Binary files /dev/null and b/bin/test/seedu/address/model/person/NameTest.class differ
diff --git a/bin/test/seedu/address/model/person/NationalityTest.class b/bin/test/seedu/address/model/person/NationalityTest.class
new file mode 100644
index 00000000000..11708c0f6c8
Binary files /dev/null and b/bin/test/seedu/address/model/person/NationalityTest.class differ
diff --git a/bin/test/seedu/address/model/person/NoteTest.class b/bin/test/seedu/address/model/person/NoteTest.class
new file mode 100644
index 00000000000..262d135666d
Binary files /dev/null and b/bin/test/seedu/address/model/person/NoteTest.class differ
diff --git a/bin/test/seedu/address/model/person/NricTest.class b/bin/test/seedu/address/model/person/NricTest.class
new file mode 100644
index 00000000000..4dab46d6f1c
Binary files /dev/null and b/bin/test/seedu/address/model/person/NricTest.class differ
diff --git a/bin/test/seedu/address/model/person/PersonTest.class b/bin/test/seedu/address/model/person/PersonTest.class
new file mode 100644
index 00000000000..8103547cb44
Binary files /dev/null and b/bin/test/seedu/address/model/person/PersonTest.class differ
diff --git a/bin/test/seedu/address/model/person/PhoneTest.class b/bin/test/seedu/address/model/person/PhoneTest.class
new file mode 100644
index 00000000000..9ecb1fcfa41
Binary files /dev/null and b/bin/test/seedu/address/model/person/PhoneTest.class differ
diff --git a/bin/test/seedu/address/model/person/UniquePersonListTest.class b/bin/test/seedu/address/model/person/UniquePersonListTest.class
new file mode 100644
index 00000000000..0857595ff1c
Binary files /dev/null and b/bin/test/seedu/address/model/person/UniquePersonListTest.class differ
diff --git a/bin/test/seedu/address/model/tag/DepartmentTest.class b/bin/test/seedu/address/model/tag/DepartmentTest.class
new file mode 100644
index 00000000000..1d89932581c
Binary files /dev/null and b/bin/test/seedu/address/model/tag/DepartmentTest.class differ
diff --git a/bin/test/seedu/address/model/tag/EmploymentTypeTest.class b/bin/test/seedu/address/model/tag/EmploymentTypeTest.class
new file mode 100644
index 00000000000..33df56f62b1
Binary files /dev/null and b/bin/test/seedu/address/model/tag/EmploymentTypeTest.class differ
diff --git a/bin/test/seedu/address/model/tag/JobTitleTest.class b/bin/test/seedu/address/model/tag/JobTitleTest.class
new file mode 100644
index 00000000000..10279841568
Binary files /dev/null and b/bin/test/seedu/address/model/tag/JobTitleTest.class differ
diff --git a/bin/test/seedu/address/model/tag/TagTest.class b/bin/test/seedu/address/model/tag/TagTest.class
new file mode 100644
index 00000000000..9cdc7ea2501
Binary files /dev/null and b/bin/test/seedu/address/model/tag/TagTest.class differ
diff --git a/bin/test/seedu/address/model/util/SampleDataUtilTest.class b/bin/test/seedu/address/model/util/SampleDataUtilTest.class
new file mode 100644
index 00000000000..61c05dd32e3
Binary files /dev/null and b/bin/test/seedu/address/model/util/SampleDataUtilTest.class differ
diff --git a/bin/test/seedu/address/storage/JsonAdaptedPersonTest.class b/bin/test/seedu/address/storage/JsonAdaptedPersonTest.class
new file mode 100644
index 00000000000..8acbbcd19dd
Binary files /dev/null and b/bin/test/seedu/address/storage/JsonAdaptedPersonTest.class differ
diff --git a/bin/test/seedu/address/storage/JsonAdaptedTagTest.class b/bin/test/seedu/address/storage/JsonAdaptedTagTest.class
new file mode 100644
index 00000000000..25c3895d24b
Binary files /dev/null and b/bin/test/seedu/address/storage/JsonAdaptedTagTest.class differ
diff --git a/bin/test/seedu/address/storage/JsonAddressBookStorageTest.class b/bin/test/seedu/address/storage/JsonAddressBookStorageTest.class
new file mode 100644
index 00000000000..57a96028cdf
Binary files /dev/null and b/bin/test/seedu/address/storage/JsonAddressBookStorageTest.class differ
diff --git a/bin/test/seedu/address/storage/JsonSerializableAddressBookTest.class b/bin/test/seedu/address/storage/JsonSerializableAddressBookTest.class
new file mode 100644
index 00000000000..87f2b2301a9
Binary files /dev/null and b/bin/test/seedu/address/storage/JsonSerializableAddressBookTest.class differ
diff --git a/bin/test/seedu/address/storage/JsonUserPrefsStorageTest.class b/bin/test/seedu/address/storage/JsonUserPrefsStorageTest.class
new file mode 100644
index 00000000000..16fc4a0bd69
Binary files /dev/null and b/bin/test/seedu/address/storage/JsonUserPrefsStorageTest.class differ
diff --git a/bin/test/seedu/address/storage/StorageManagerTest.class b/bin/test/seedu/address/storage/StorageManagerTest.class
new file mode 100644
index 00000000000..550394f167a
Binary files /dev/null and b/bin/test/seedu/address/storage/StorageManagerTest.class differ
diff --git a/bin/test/seedu/address/testutil/AddressBookBuilder.class b/bin/test/seedu/address/testutil/AddressBookBuilder.class
new file mode 100644
index 00000000000..824a9eb6257
Binary files /dev/null and b/bin/test/seedu/address/testutil/AddressBookBuilder.class differ
diff --git a/bin/test/seedu/address/testutil/Assert.class b/bin/test/seedu/address/testutil/Assert.class
new file mode 100644
index 00000000000..20ef19109ab
Binary files /dev/null and b/bin/test/seedu/address/testutil/Assert.class differ
diff --git a/bin/test/seedu/address/testutil/EditPersonDescriptorBuilder.class b/bin/test/seedu/address/testutil/EditPersonDescriptorBuilder.class
new file mode 100644
index 00000000000..62d5cc31bba
Binary files /dev/null and b/bin/test/seedu/address/testutil/EditPersonDescriptorBuilder.class differ
diff --git a/bin/test/seedu/address/testutil/PersonBuilder.class b/bin/test/seedu/address/testutil/PersonBuilder.class
new file mode 100644
index 00000000000..89f67aa2bd7
Binary files /dev/null and b/bin/test/seedu/address/testutil/PersonBuilder.class differ
diff --git a/bin/test/seedu/address/testutil/PersonUtil.class b/bin/test/seedu/address/testutil/PersonUtil.class
new file mode 100644
index 00000000000..50296d0dece
Binary files /dev/null and b/bin/test/seedu/address/testutil/PersonUtil.class differ
diff --git a/bin/test/seedu/address/testutil/SerializableTestClass.class b/bin/test/seedu/address/testutil/SerializableTestClass.class
new file mode 100644
index 00000000000..590d11e3cb3
Binary files /dev/null and b/bin/test/seedu/address/testutil/SerializableTestClass.class differ
diff --git a/bin/test/seedu/address/testutil/TestUtil.class b/bin/test/seedu/address/testutil/TestUtil.class
new file mode 100644
index 00000000000..7d9c101734e
Binary files /dev/null and b/bin/test/seedu/address/testutil/TestUtil.class differ
diff --git a/bin/test/seedu/address/testutil/TypicalIndexes.class b/bin/test/seedu/address/testutil/TypicalIndexes.class
new file mode 100644
index 00000000000..395630d5892
Binary files /dev/null and b/bin/test/seedu/address/testutil/TypicalIndexes.class differ
diff --git a/bin/test/seedu/address/testutil/TypicalPersons.class b/bin/test/seedu/address/testutil/TypicalPersons.class
new file mode 100644
index 00000000000..0dd83a0ceb0
Binary files /dev/null and b/bin/test/seedu/address/testutil/TypicalPersons.class differ
diff --git a/bin/test/seedu/address/ui/TestFxmlObject.class b/bin/test/seedu/address/ui/TestFxmlObject.class
new file mode 100644
index 00000000000..02862d1d9e5
Binary files /dev/null and b/bin/test/seedu/address/ui/TestFxmlObject.class differ
diff --git a/bin/test/seedu/address/ui/UiPartTest$TestUiPart.class b/bin/test/seedu/address/ui/UiPartTest$TestUiPart.class
new file mode 100644
index 00000000000..0b088fbd005
Binary files /dev/null and b/bin/test/seedu/address/ui/UiPartTest$TestUiPart.class differ
diff --git a/bin/test/seedu/address/ui/UiPartTest.class b/bin/test/seedu/address/ui/UiPartTest.class
new file mode 100644
index 00000000000..d3f8a6510c7
Binary files /dev/null and b/bin/test/seedu/address/ui/UiPartTest.class differ
diff --git a/bin/test/view/UiPartTest/invalidFile.fxml b/bin/test/view/UiPartTest/invalidFile.fxml
new file mode 100644
index 00000000000..67680946732
--- /dev/null
+++ b/bin/test/view/UiPartTest/invalidFile.fxml
@@ -0,0 +1 @@
+Not a valid FXML file
diff --git a/bin/test/view/UiPartTest/validFile.fxml b/bin/test/view/UiPartTest/validFile.fxml
new file mode 100644
index 00000000000..bab836af0db
--- /dev/null
+++ b/bin/test/view/UiPartTest/validFile.fxml
@@ -0,0 +1,4 @@
+
+
+
+Hello World!
diff --git a/bin/test/view/UiPartTest/validFileWithFxRoot.fxml b/bin/test/view/UiPartTest/validFileWithFxRoot.fxml
new file mode 100644
index 00000000000..1a8b2c9e4d3
--- /dev/null
+++ b/bin/test/view/UiPartTest/validFileWithFxRoot.fxml
@@ -0,0 +1,6 @@
+
+
+
+ Hello World!
+
diff --git a/build.gradle b/build.gradle
index 0db3743584e..da050e5962d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -65,8 +65,12 @@ dependencies {
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: jUnitVersion
}
+run {
+ enableAssertions = true
+}
+
shadowJar {
- archiveFileName = 'addressbook.jar'
+ archiveFileName = '[CS2103T-F14-2][HRelper].jar'
}
defaultTasks 'clean', 'test'
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index ff3f04abd02..e4fe527ca6f 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -9,51 +9,43 @@ You can reach us at the email `seer[at]comp.nus.edu.sg`
## Project team
-### John Doe
+### Chen Xiangrui
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/chen-xiangrui)]
-* Role: Project Advisor
+- Role: Project Advisor
-### Jane Doe
+### Chen Xiangyun
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/chenxy12345)]
-* Role: Team Lead
-* Responsibilities: UI
+- Role: Team Lead
-### Johnny Doe
+### Woo Yong Qing
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/wyongqiing)]
-* Role: Developer
-* Responsibilities: Data
+- Role: Developer
-### Jean Doe
+### David Foo
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/davidfoo07)]
-* Role: Developer
-* Responsibilities: Dev Ops + Threading
+- Role: Developer
+- Responsibilities: Backend + Testing
-### James Doe
+### Boo Wen Jun
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/wj200)]
-* Role: Developer
-* Responsibilities: UI
+- Role: Developer
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 743c65a49d2..801a919fd49 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,29 +1,55 @@
----
-layout: page
-title: Developer Guide
----
-* Table of Contents
-{:toc}
+Developer Guide
+=======
+
+## Table of Contents
+
+1. [Acknowledgements](#acknowledgements)
+2. [Setting up, getting started](#setting-up-getting-started)
+3. [Design](#design)
+ - [Architecture](#architecture)
+ - [Main components of the architecture](#main-components-of-the-architecture)
+ - [How the architecture components interact with each other](#how-the-architecture-components-interact-with-each-other)
+ - [UI Component](#ui-component)
+ - [Logic Component](#logic-component)
+ - [Model Component](#model-component)
+ - [Storage Component](#storage-component)
+ - [Common Classes](#common-classes)
+4. [Implementation](#implementation)
+ - [Undo/Redo Feature](#proposed-undoredo-feature)
+5. [Documentation, Logging, Testing, Configuration, DevOps](#documentation-logging-testing-configuration-dev-ops)
+6. [Appendix: Requirements](#appendix-requirements)
+ - [Product Scope](#product-scope)
+ - [User Stories](#user-stories)
+ - [Use Cases](#use-cases)
+ - [Non-Functional Requirements](#non-functional-requirements)
+ - [Glossary](#glossary)
+7. [Appendix: Instructions for Manual Testing](#appendix-instructions-for-manual-testing)
+8. [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}
+HRelper is built upon the AddressBook-Level3 project created by the SE-EDU initiative.
+It incorporates the following third-party libraries:
+
+* JavaFX – for building the graphical user interface (GUI)
+* Jackson – for handling JSON serialization and deserialization
+* JUnit 5 – for writing and running unit tests
--------------------------------------------------------------------------------------------------------------------
## **Setting up, getting started**
-
Refer to the guide [_Setting up and getting started_](SettingUp.md).
--------------------------------------------------------------------------------------------------------------------
-
## **Design**
-:bulb: **Tip:** The `.puml` files used to create diagrams in this document `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 `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,9 +62,13 @@ Given below is a quick overview of main components and how they interact with ea
**Main components of the architecture**
-**`Main`** (consisting of classes [`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)) is in charge of the app launch and shut down.
+**`Main`** (consisting of classes [`Main`](https://github.com/AY2425S2-CS2103T-F14-2/tp/tree/master/src/main
+/java/seedu/address/Main.java)
+and [`MainApp`](https://github.com/AY2425S2-CS2103T-F14-2/tp/tree/master/src/main/java/seedu/address/MainApp.java)) is
+in charge of the app launch and shut down.
+
* At app launch, it initializes the other components in the correct sequence, and connects them up with each other.
-* At shut down, it shuts down the other components and invokes cleanup methods where necessary.
+* At shut down, it shuts down the other components and invokes cleanup methods where necessary
The bulk of the app's work is done by the following four components:
@@ -51,16 +81,21 @@ The bulk of the app's work is done by the following four components:
**How the architecture components interact with each other**
-The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `delete 1`.
+The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues
+the command `delete 1`.
Each of the four main components (also shown in the diagram above),
* defines its *API* in an `interface` with the same name as the Component.
-* implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding API `interface` mentioned in the previous point.
+* implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding
+ API `interface` mentioned in the previous point.
-For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
+For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using
+the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component
+through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the
+implementation of a component), as illustrated in the (partial) class diagram below.
@@ -68,13 +103,21 @@ The sections below give more details of each component.
### 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/AY2425S2-CS2103T-F14-2/tp/tree/master/src/main/java/seedu/address/ui/Ui.java)

-The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
+The UI consists of a `MainWindow` that is made up of parts
+e.g.`CommandBox`, `ResultDisplay`, `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` 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/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,
@@ -85,13 +128,15 @@ The `UI` component,
### 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/AY2425S2-CS2103T-F14-2/tp/tree/master/src/main/java/seedu/address/logic/Logic.java)
Here's a (partial) class diagram of the `Logic` component:
-The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("delete 1")` API call as an example.
+The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("delete 1")` API
+call as an example.

@@ -100,10 +145,13 @@ The sequence diagram below illustrates the interactions within the `Logic` compo
How the `Logic` component works:
-1. When `Logic` is called upon to execute a command, it is passed to an `AddressBookParser` object which in turn creates a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command.
-1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which is executed by the `LogicManager`.
+1. When `Logic` is called upon to execute a command, it is passed to an `AddressBookParser` object which in turn creates
+ a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command.
+1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which
+ is executed by the `LogicManager`.
1. The command can communicate with the `Model` when it is executed (e.g. to delete a person).
- Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and the `Model`) to achieve.
+ Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take
+ several interactions (between the command object and the `Model`) to achieve.
1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command:
@@ -111,39 +159,53 @@ 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.
-* 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.
+
+* 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.
+* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser`
+ interface so that they can be treated similarly where possible e.g, during testing.
### Model component
-**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/AY2425S2-CS2103T-F14-2/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 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)
+* stores the HRelper 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 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.
-
+
-
### 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/AY2425S2-CS2103T-F14-2/tp/tree/master/src/main/java/seedu/address/storage/Storage.java)
The `Storage` component,
-* can save both address book data and user preference data in JSON format, and read them back into corresponding objects.
-* inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
-* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`)
+
+* can save both HRelper data and user preference data in JSON format, and read them back into corresponding objects.
+* inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only
+ the functionality of only one is needed).
+* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects
+ that belong to the `Model`)
### Common classes
@@ -159,25 +221,34 @@ This section describes some noteworthy details on how certain features are imple
#### Proposed Implementation
-The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the following operations:
+The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo
+history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the
+following operations:
-* `VersionedAddressBook#commit()` — Saves the current address book state in its history.
-* `VersionedAddressBook#undo()` — Restores the previous address book state from its history.
-* `VersionedAddressBook#redo()` — Restores a previously undone address book state from its history.
+* `VersionedAddressBook#commit()`— Saves the current HRelper state in its history.
+* `VersionedAddressBook#undo()`— Restores the previous HRelper state from its history.
+* `VersionedAddressBook#redo()`— Restores a previously undone HRelper state from its history.
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
+These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()`
+and `Model#redoAddressBook()` respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
-Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state.
+Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the
+initial address book state, and the `currentStatePointer` pointing to that single address book state.

-Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state.
+Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command
+calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes
+to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book
+state.

-Step 3. The user executes `add n/David …` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`.
+Step 3. The user executes `add 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`.

@@ -185,7 +256,9 @@ Step 3. The user executes `add n/David …` to add a new person. The `add` co
-Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state.
+Step 4. The user now decides that adding the 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.

@@ -206,17 +279,23 @@ Similarly, how an undo operation goes through the `Model` component is shown bel

-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.
+The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once
+to the right, pointing to the previously undone state, and restores the address book to that state.
:information_source: **Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
-Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged.
+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.

-Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …` command. This is the behavior that most modern desktop applications follow.
+Step 6. The user 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.

@@ -229,20 +308,13 @@ The following activity diagram summarizes what happens when a user executes a ne
**Aspect: How undo & redo executes:**
* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+ * Pros: Easy to implement.
+ * Cons: May have performance issues in terms of memory usage.
* **Alternative 2:** Individual command knows how to undo/redo by
itself.
- * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted).
- * Cons: We must ensure that the implementation of each individual command are correct.
-
-_{more aspects and alternatives to be added}_
-
-### \[Proposed\] Data archiving
-
-_{Explain here how the data archiving feature will be implemented}_
-
+ * 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.
--------------------------------------------------------------------------------------------------------------------
@@ -262,44 +334,190 @@ _{Explain here how the data archiving feature will be implemented}_
**Target user profile**:
+HRelper is designed for HR teams who:
+
+* manage a significant number of employee records and contact details.
+* find traditional spreadsheets inefficient or cumbersome for day-to-day contact management.
* has a need to manage a significant number of contacts
+* require a structured system to track details like joining dates, NRICs, and other personal data.
* prefer desktop apps over other types
* can type fast
* prefers typing to mouse interactions
* is reasonably comfortable using CLI apps
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
-
+**Value proposition**: Enables HR to quickly access and manage employee and job seeker information, streamlining
+recruitment and communication within the company.
### User stories
Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-| Priority | As a … | I want to … | So that I can… |
-| -------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------- |
-| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App |
-| `* * *` | user | add a new person | |
-| `* * *` | user | delete a person | remove entries that I no longer need |
-| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list |
-| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident |
-| `*` | user with many persons in the address book | sort persons by name | locate a person easily |
-
-*{More to be added}*
+| Priority | As a … | I want to … | So that I can… |
+|----------|---------|-----------------------------------------------|--------------------------------------------------------------------------|
+| `* * *` | user | I can add a profile | so that I can store employee details in the address book. |
+| `* * *` | user | I can delete the employees profile | so that I can removed outdated or incorrect records. |
+| `* * *` | user | I can view a profiles | so that I can get employee information. |
+| `* * ` | user | I can edit the profile | so that i can update their information when needed. |
+| `* *` | user | I can filter contacts by department | so that I can quickly see all employees in a specific department. |
+| `* *` | user | I can filter contacts by employement type | so that I can quickly see all employees with a specific employment type. |
+| `* *` | user | I can filter contacts by job title | so that I can quickly see all employees with a specific job title. |
+| `* *` | user | I can add an extra optional note to a profile | so that I am aware of additional information about an employee. |
### Use cases
+(For all use cases below, the **System** is the `HRelper` and the **Actor** is the `HR manager (HR)`, unless specified
+otherwise)
+
+**Use case: Add an Employee Profile**
+
+**MSS **
+
+1. HR requests to add an employee profile.
+
+2. HRelper prompts for details of the employee.
+
+3. HR fills in the details.
+
+4. HRelper requests HR to confirm the details.
+
+5. HR confirms the details.
+
+6. HRelper adds the employee to the system.
+
+ Use case ends.
+
+**Extensions**
+
+* 3a. HR enters invalid data for one or more attributes.
+ * 3a1. HRelper displays an error message indicating which field is invalid and the expected format.
+ * 3a2. HR corrects the invalid entry.
+ Use case resumes at step 3.
+* 4a. HR decides to change details.
+ * 4a1. HR cancels confirmation.
+ Use case resumes at step 3.
+
+* 4b. HRelper finds an existing employee profile by tags. (Department, Employment Type or Job Title)
+ Use case resumes at step 3.
+
+* 5a. HR loses connection.
+
+ * 5a1. HRelper saves details.
+
+ * 5a2. HRelper prompts HR to continue where they left off.
+ Use case resumes at step 3.
+
+**Use case: Find Employees by Department**
+
+**MSS**
+
+1. HR requests to find employees by department.
+2. HRelper prompts for the department keyword.
+3. HR enters the department keyword.
+4. HRelper displays a list of employees in the specified department.
+ Use case ends.
+
+**Extensions**
+
+* 3a. HR enters invalid characters in the department keyword.
+ * 3a1. HRelper shows an error message explaining valid department input format.
+ Use case resumes at step 2.
+* 4a. No employees found in the specified department.
+ * 4a1. HRelper shows an empty list.
+
+ Use case ends.
+
+**Use case: Find Employees by Job Title**
+
+**MSS**
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+1. HR requests to find employees by job title.
+2. HRelper prompts for the job title keyword.
+3. HR enters the job title keyword.
+4. HRelper displays a list of employees with the specified job title.
+ Use case ends.
-**Use case: Delete a person**
+**Extensions**
+
+* 3a. HR enters invalid characters in the job title keyword.
+ * 3a1. HRelper shows an error message explaining valid job title input format.
+ Use case resumes at step 2.
+* 3b. HR enters a keyword that is too short or ambiguous.
+ * 3b1. HRelper suggests using more specific keywords.
+ Use case resumes at step 2.
+* 4a. No employees found with the specified job title.
+ * 4a1. HRelper shows an empty list. Use case ends.
+
+**Use case: Find Employees by Employment Type**
+
+**MSS**
+
+1. HR requests to find employees by employment type.
+2. HRelper prompts for the employment type keyword.
+3. HR enters the employment type keyword.
+4. HRelper displays a list of employees with the specified employment type.
+ Use case ends.
+
+**Extensions**
+
+* 3a. HR enters invalid characters in the employment type keyword.
+ * 3a1. HRelper shows an error message explaining valid employment type input format.
+ Use case resumes at step 2.
+* 4a. No employees found with the specified employment type.
+ * 4a1. HRelper shows an empty list.
+ Use case ends.
+
+**Use case: View Employee Details by Full Name or Surname**
**MSS**
-1. User requests to list persons
-2. AddressBook shows a list of persons
-3. User requests to delete a specific person in the list
-4. AddressBook deletes the person
+1. HR enters the employee's full name.
+2. HRelper displays the comprehensive profile of the specified employee.
+ Use case ends.
+
+Extensions
- Use case ends.
+* 1a. The given name does not match any employee in the system.
+ * 1a1. HRelper shows an error message.
+ Use case resumes at step 2.
+* 1b. Multiple employees share the same name.
+ * 1b1. HRelper displays a list of all matching employees.
+ Use case ends.
+* 2a. The employee profile has incomplete information.
+ * 2a1. HRelper displays the available information with indicators for missing fields.
+ Use case ends.
+
+**Use case: Add/Edit Note to Employee Profile by Index**
+
+**MSS**
+
+1. HR requests to add or edit a note for an employee.
+2. HR enters the employee index and new note content.
+3. HRelper updates the employee's profile with the new note.
+
+ Use case ends.
+
+Extensions
+
+* 3a. The given index is invalid.
+ * 3a1. HRelper shows an error message.
+ Use case resumes at step 2.
+* 3b. HR enters empty note content.
+ * 3b1. HRelper removes any existing note from the employee profile.
+ * 3b2. HRelper confirms the note has been removed.
+ Use case ends.
+* 4a. HR tries to add a note that exceeds the character limit.
+ * 4a1. HRelper shows an error message indicating the character limit.
+ Use case resumes at step 3.
+
+**Use case: Delete an Employee Profile**
+
+**MSS**
+
+1. HR requests to list employees.
+2. HRelper shows a list of employees.
+3. HR requests to delete a specific employee in the list.
+4. HRelper deletes the employee.
+
+ Use case ends.
**Extensions**
@@ -309,24 +527,55 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
* 3a. The given index is invalid.
- * 3a1. AddressBook shows an error message.
+ * 3a1. HRelper shows an error message.
Use case resumes at step 2.
-*{More to be added}*
+**Use case: Add/Edit/Remove Note to Employee Profile by Index**
-### Non-Functional Requirements
+**MSS**
-1. Should work on any _mainstream OS_ as long as it has Java `17` 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.
+1. HR requests to add or edit a note for an employee.
+2. HR enters the employee index and new note content.
+3. HRelper updates the employee's profile with the new note.
+ Use case ends.
-*{More to be added}*
+**Extensions**
+
+* 3a. The given index is invalid.
+ * 3a1. HRelper shows an error message.
+ Use case resumes at step 2.
+* 3b. HR enters empty note content.
+ * 3b1. HRelper removes any existing note from the employee profile.
+ Use case ends.
+
+### Non-Functional Requirements
+
+1. Should work on any _mainstream OS_ as long as it has Java `17` 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.
+4. Managing contacts will remain as the core feature in all iterations.
+5. The application should not crash for any input given by the user.
+6. The application will remain as a CLI based application.
### Glossary
* **Mainstream OS**: Windows, Linux, Unix, MacOS
+* **HRelper**: A Human Resource management tool for managing employee profiles efficiently.
* **Private contact detail**: A contact detail that is not meant to be shared with others
+* **UI**: User Interface - the space where interactions between humans (users) and machines (software or hardware) occur
+* **Sequence Diagram**: A visual representation of the sequence of interactions between different objects, components,
+ or actors in a system over time
+* **API**: Application Programming Interface - A set of rules, protocols, and tools that allows different software
+ applications to communicate and interact with each other
+* **GUI**: Graphical User Interface - A type of user interface that allows users to interact with software applications
+ or devices through graphical elements rather than using text-based commands
+* **JavaFx**: A Java library used for building modern GUIs
+* **JSON**: An open standard file format and data interchange format that uses human-readable text to store and transmit
+ data objects consisting of attribute–value pairs and arrays
+* **CLI app**: Command-Line Interface application - A software application that allows users to interact with it through
+ a text-based interface by typing commands in a console or terminal
--------------------------------------------------------------------------------------------------------------------
@@ -334,8 +583,8 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
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.
+
Note: These instructions only provide a starting point for testers to work on;
+testers are expected to do more exploratory testing.
@@ -343,40 +592,132 @@ testers are expected to do more *exploratory* testing.
1. Initial launch
- 1. Download the jar file and copy into an empty folder
-
- 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
+ 1. Download the jar file and copy into an empty folder
+ 2. Open a terminal and `cd` into the folder with the jar file.
+ 3. Run `java -jar "[CS2103T-F14-2][HRelper]".jar`.
+ Expected: An empty address book will be shown.
+ The window size may not be optimum.
1. Saving window preferences
- 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
+ 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
- 1. Re-launch the app by double-clicking the jar file.
+ 1. Re-launch the app by rerunning `java -jar "[CS2103T-F14-2][HRelper]".jar` in the terminal.
Expected: The most recent window size and location is retained.
-1. _{ more test cases … }_
-
### Deleting a person
1. Deleting a person while all persons are being shown
- 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
-
- 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated.
+ 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
- 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
+ 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.
- 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous.
+ 1. Test case: `delete 0`
+ Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
-1. _{ more test cases … }_
+ 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
+ Expected: Similar to previous.
### Saving data
-1. Dealing with missing/corrupted data files
-
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
-
-1. _{ more test cases … }_
+1. Testing data persistence across sessions
+
+ 1. Add a new person using the `add` command.
+
+ 2. Close the app.
+
+ 3. Re-launch the app.
+ Expected: The newly added person should still be present in the list.
+
+You can try out other data changing commands such as `clear`,`delete`, `edit`.
+
+2. Dealing with missing data file
+
+ 1. Exit HRelper, if it is running.
+ 2. delete the `addressbook.json` file inside the folder named `data`. It is located in the same folder as the jar
+ file.
+ 3. Relaunch the app.
+ Expected: The app should create a new `addressbook.json` file filled with sample data.
+
+## **Appendix: Planned Enhancement**
+
+**Team Size** : 5
+
+1. **Add a confirmation window before executing sensitive commands** (e.g., edit, delete).
+ Currently, once a command is entered, the system immediately executes it without confirmation.
+ This can be risky, especially for delete operations. We plan to add a pop-up confirmation dialog
+ before executing critical actions to prevent accidental edits or deletions.
+2. **Implement `undo` functionality.**
+ There is currently no way to revert a mistake. If a user accidentally deletes or modifies a record, it cannot be
+ recovered. We plan to introduce an undo feature that allows users to revert the most recent command that modified
+ data.
+3. **Implement `redo` functionality.**
+ After undoing a command, the user might want to reapply it. Currently, this requires retyping the command manually.
+ We plan to add a redo feature to restore the most recently undone command.
+4. **Allow multiple deletions in a single command.**
+ Currently, the delete command only supports deleting one contact at a time. We plan to support multiple deletions
+ using comma-separated indexes, e.g., `delete 1, 3, 5` to improve user efficiency.
+5. **Relax address format constraints.**
+ Currently, addresses must include a Singapore-style postal code with specific district prefixes. To support global
+ users and remote workers, we plan to relax this validation to allow international formats or omit postal codes
+ altogether.
+6. **Add support for data import/export using CSV files.**
+ Currently, HRelper stores and reads contact data in JSON format, which may not be familiar to non-technical users. HR
+ teams often maintain contact records in Excel or Google Sheets and may need to perform bulk updates, generate
+ reports, or share data externally.
+ We plan to introduce the ability to import data from CSV files, allowing HR teams to easily migrate existing records
+ into HRelper without manually entering each contact. Similarly, we will support exporting current records to CSV
+ format, enabling convenient data backup, offline reporting, and integration with other HR tools.
+
+ * This feature will:
+ 1. Reduce manual entry and setup time
+ 2. Improve compatibility with spreadsheet tools
+ 3. Allow HR to generate and share filtered reports easily
+ 4. Provide error messages when invalid or missing fields are detected during import
+
+7. **Implement a command history tracker**.
+ Currently, HRelper does not store a history of previously entered commands. This can be inconvenient for users who
+ wish to repeat a past command, especially if the command was long or complex (e.g., multi-field `add` or `edit`
+ commands).
+
+ We plan to implement a **command history tracker** that:
+
+ - Maintains a chronological log of previously executed commands.
+ - Allows users to **navigate the history using arrow keys** (↑ / ↓) in the command box.
+ - Enables users to **reuse, modify, or re-execute** previous commands with ease.
+
+ This enhancement improves usability by reducing the need for repetitive typing and helps users correct or retry
+ failed commands quickly.
+8. **Enable tag auto-suggestions when typing departments, job titles, or employment types.**
+ Currently, users must remember and manually input the exact department/job title format. This can lead to errors or
+ inconsistencies.
+ We plan to implement autocomplete suggestions when the user begins typing tags (e.g., “Fin” suggests “Finance”) to
+ improve speed, accuracy, and consistency in data entry.
+9. **Add a mini HR dashboard for quick data overview.**
+ Currently, HRelper only displays contact information. For HR users managing a large database, a dashboard summarizing
+ key statistics would be useful.
+ We plan to introduce a sidebar or pop-up dashboard that shows:
+
+ - Total number of employees
+ - Department breakdown
+ - Employment type distribution
+ - Gender and nationality statistics
+ - This enhancement gives HR teams quick insights at a glance and supports workforce planning.
+
+10. **Enable editing multiple entries in one command.**
+ Currently, the `edit` command only supports updating one person at a time. In many HR workflows, bulk updates are
+ needed (e.g., changing job titles for a group of interns or updating department names after restructuring).
+
+ We plan to enhance the `edit` command to support **batch editing** using comma-separated indexes and a shared set of
+ fields.
+ For example:
+ `edit 2, 4, 5 t/IT/Intern/Software Intern`
+ This would apply the same tag update to persons at index 2, 4, and 5.
+
+ - The command will apply the same changes to all specified records.
+ - If any index is invalid, the system will display an error message and abort the operation to avoid partial
+ updates.
+ - This will significantly reduce repetitive commands and improve productivity when handling common changes.
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 27c2d1cf16c..6e2162a5841 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,39 +1,88 @@
---
layout: page
-title: User Guide
+title: HRelper User Guide
---
+--------------------------------------------------------------------------------------------------------------------
+## Hello HR! Meet HRelper
+Welcome to HRelper, your trusted assistant for managing employee records with ease and speed.
+We understand that working in HR means wearing many hats — from onboarding new hires and updating staff details to managing departments and tracking employment history. It can quickly become overwhelming.
+
+That’s where HRelper comes in. Designed to simplify and streamline your workflow, HRelper helps you manage your employee database efficiently and confidently — so you can spend less time on spreadsheets and more time focusing on people.
-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}
+### Table of Contents
+
+- [Quick start](#quick-start)
+- [Features](#features)
+ - [Viewing help](#viewing-help--help)
+ - [Adding a person](#adding-a-person-add)
+ - [Listing all persons](#listing-all-persons--list)
+ - [Viewing a profile](#viewing-a-profile-view)
+ - [Returning to home view](#returning-to-home-view)
+ - [Editing a person](#editing-a-person--edit)
+ - [Filtering by](#filtering-by-findby)
+ - [Deleting a person](#deleting-a-person--delete)
+ - [Adding a note](#adding-a-note--note)
+ - [Clearing all entries](#clearing-all-entries--clear)
+ - [Exiting the program](#exiting-the-program--exit)
+ - [Saving the data](#saving-the-data)
+ - [Editing the data file](#editing-the-data-file)
+ - [Archiving data files](#archiving-data-files-coming-in-v20)
+- [FAQ](#faq)
+ - [Q1: Will my data be lost if I close the app?](#a-idq1aq1-what-happens-if-i-close-the-app-will-my-data-be-lost)
+ - [Q2: Can I search by job title or department?](#a-idq2aq2-can-i-search-for-employees-by-job-title-or-departmentbr)
+- [Known issues](#known-issues)
+- [Command summary](#command-summary)
+- [Valid Departments, Employment Types, Job Titles](#valid-departments-employment-types-job-titles-of-hrelper)
+- [Valid Short-Forms](#valid-short-forms-of-hrelper)
--------------------------------------------------------------------------------------------------------------------
+## ⚠️ Current HRelper Prototype Overview
+The current version of the HRelper is a prototype designed to showcase its core functionality.
+
+* At present, the prototype is tailored to Singapore, meaning that phone numbers and NRICs are configured for Singapore-based operations.
+* Since this is just a prototype of how our HRelper works, in real world scenarios, we will customise the valid department list according to the company's needs. Each company should populate the valid department before using HRelper.
+* Attributes marked with an asterisk (*) indicate that they are in their current form because they follow the structure of the prototype.
## Quick start
1. Ensure you have Java `17` or above installed in your Computer.
**Mac users:** Ensure you have the precise JDK version prescribed [here](https://se-education.org/guides/tutorials/javaInstallationMac.html).
-1. Download the latest `.jar` file from [here](https://github.com/se-edu/addressbook-level3/releases).
+1. Download the latest `.jar` file from [here](https://github.com/AY2425S2-CS2103T-F14-2/tp/releases).
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+1. Copy the file to the folder you want to use as the _home folder_ for HRelper.
-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.
- 
+1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar "[CS2103T-F14-2][HRelper]".jar` command to run the application.
+ A GUI similar to the below should appear in a few seconds.
+
+
+ This is how the app should look like after containing some data:
+
+
+
+If there is no sample data, it could be where under the same directory of this jar file, there is a data file and inside there is a addressbook.json file. For eg: ./data/addressbook.json, please remove it for sample data to load.
1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.
Some example commands you can try:
- * `list` : Lists all contacts.
+ * `list` : Lists all contacts with full attributes.
- * `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.
+ * `add n/John Doe p/98765432 e/johnd@example.com ic/T0312345A g/Male d/02-Jan-2001 j/15-Apr-2025 nat/Singaporean a/311, Clementi Ave 2, #02-25/119278 t/Finance/Full-Time/Financial Analyst` : Adds a contact named `John Doe` to the Address Book.
* `delete 3` : Deletes the 3rd contact shown in the current list.
* `clear` : Deletes all contacts.
+ * `view Lee` : Views the contact by their name.
+
+ * `edit 2 n/Betsy Crower`: Edits the name of the 2nd person to be `Betsy Crower`.
+
+ * `findByDepartment Finance` : Lists all contacts in this specific department
+
+ * `note`: Adds optional remarks to people in their address book and edit it if required.
+
* `exit` : Exits the app.
1. Refer to the [Features](#features) below for details of each command.
@@ -49,11 +98,8 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo
* 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`.
-* Items in square brackets are optional.
- e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`.
-
-* Items with `…` after them can be used multiple times including zero times.
- e.g. `[t/TAG]…` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc.
+* Words in `SQUARE BRACKETS [ ]` are optional parameters.
+ e.g. in `edit 1 [n/NAME]`, `NAME` is an optional parameter
* 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.
@@ -77,56 +123,132 @@ Format: `help`
Adds a person to the address book.
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+Format: `add n/NAME p/PHONE_NUMBER e/EMAIL ic/NRIC g/GENDER d/DOB j/DATE OF JOINING nat/NATIONALITY a/ADDRESS/POSTAL CODE t/DEPARTMENT/EMPLOYMENTTYPE/JOBTITLE`
+
+* Names are case-insensitive. The profile will automatically capitalise the first letter of each word and convert all other letters to lowercase.
+* Phone numbers must be exactly 8 digits long and start with 6, 8, or 9.*
+* NRIC should start with S, T, F, or G, followed by 7 digits, and end with a capital letter.*
+* Gender is case-insensitive but will only take in Male, Female or Other.*
+* All dates (DOB or Date of Joining) must follow one of these formats: dd-MMM-yyyy, dd/MM/yyyy, dd.MM.yyyy, yyyy-MM-dd, or dd-MM-yyyy ->
+ **Single-digit days and months must be zero-padded (e.g., use 01 instead of 1)**
+* DOB must be a valid date that is not in the future.
+* Date of Joining must be a valid date that is after DOB. Future dates are allowed to account for upcoming hires. (If the contract date is yet to be confirmed, please select the first day of the joining month.)
+* Nationality is case-insensitive but follows a pre-defined set of common nationalities. In the rare case where a nationality is not specified, choose 'Other'.
+* Address follows postal codes (specifically, the Postal Sector) defined by the [Urban Redevelopment Authority (URA)](https://www.ura.gov.sg/Corporate/-/media/Corporate/Property/PMI-Online/List_Of_Postal_Districts.pdf).
+* Tag fields (i.e. Department, Employment Type, Job Title) are case-insensitive. Additionally, certain short forms are valid for Department.
+
+**To note: Each person is unique based on their NRIC**
-
:bulb: **Tip:**
-A person can have any number of tags (including 0)
-
Examples:
-* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01`
-* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal`
+* `add n/John Doe p/98765432 e/johnd@example.com ic/T0312345A g/Male d/02-Jan-2001 j/15-Apr-2025 nat/Singaporean a/311, Clementi Ave 2, #02-25/119278 t/Finance/Full-Time/Financial Analyst`
+
### Listing all persons : `list`
-Shows a list of all persons in the address book.
+Shows a list of all persons in the address book with full attributes.
Format: `list`
+### Viewing a profile: `view`
+
+Displays the full profile of an employee by matching their **full name**.
+
+Format: `view FULLNAME`
+
+* The search is **case-insensitive**. e.g `hans` will match `Hans`
+* ⚠️ Order matters for full names. e.g. `Hans Bo` will not match `Bo Hans`
+* Only the name is searched.
+* **Exact word match only** - prefix names won't be matched. e.g. `Han` will not match `Hans`
+* Person matching the full name will be returned.
+e.g. `view Hans Bo` will return `Hans Bo`
+
+Examples:
+* `view David Li`
+
+
+
+### Returning to Home View:
+
+After viewing an employee’s profile, you can return to the main Home view, simply:
+
+- **Click** on **Home → Back to Home** in the top menu bar
+
+HRelper will return to the overview page and display all employees again, with a message:
+**Returned to Home**
+
+
Before returning to Home
After returning to Home
+
SHORTCUT: press F2 to navigate back to home page
+
### Editing a person : `edit`
Edits an existing person in the address book.
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [g/GENDER] [d/DOB] [j/DATE OF JOINING] [nat/NATIONALITY] [a/ADDRESS/POSTAL CODE] [t/DEPARTMENT/EMPLOYMENT TYPE/JOB TITLE]`
* 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, …
+* Square brackets [ ] represent optional fields
* 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.
+* When editing tags, even if editing only one item out of all, you need to include all items
+* Note that editing of NRIC is not allowed
+* *Refer back to `add` command for validity of inputs
+
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.
+* `edit 2 n/Betsy Crower` Edits the name of the 2nd person to be `Betsy Crower`.
+* `edit 1 t/HR/Full-Time/HR Coordinator` Edits the tag of the 1st person to be `HR/Full-Time/HR Coordinator`.
-### Locating persons by name: `find`
+### Filtering by: `findBy...`
+Filters the contacts by their department, job title, or employment type.
-Finds persons whose names contain any of the given keywords.
+*Refer to table of valid inputs and short-forms for HRelper
-Format: `find KEYWORD [MORE_KEYWORDS]`
+#### `findByDepartment`
+Format: `findByDepartment KEYWORD`
-* 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`
+* Finds contacts who belong to departments that match the specified keyword.
+* Search is case-insensitive (e.g., "finance" will match "Finance").
+* Accepts department short forms (e.g., "HR" will match "Human Resources").
+* For partial matches, keyword must contain at least 3 consecutive letters of the department name.
+* Only alphabetic characters and the '&' symbol are allowed in department search terms.
Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
- 
+* `findByDepartment Finance` returns all contacts in the Finance department.
+* `findByDepartment HR` returns all contacts in the Human Resources department.
+* `findByDepartment Inf` returns all contacts in the Information Technology department.
+* `findByDepartment Tec` returns all contacts in the Information Technology department.
+
+#### `findByJobTitle`
+Format: `findByJobTitle KEYWORD`
+
+* Finds contacts whose job titles match the specified keyword.
+* Search is case-insensitive.
+* Will match if the keyword matches a full word in the job title.
+* For partial matches, keyword must contain at least 3 consecutive letters of a word in the job title.
+* Only alphabetic characters are allowed in job title search terms.
+
+Examples:
+* `findByJobTitle Engineer` returns all engineers.
+* `findByJobTitle Dev` returns all developers.
+* `findByJobTitle Coord` returns all coordinators.
+
+#### `findByEmploymentType`
+Format: `findByEmploymentType EMPLOYMENT_TYPE`
+
+* Finds contacts with the specified employment type.
+* Search is case-insensitive.
+* Will match if the keyword matches a full word in the job title.
+* For partial matches, keyword must contain at least 3 consecutive letters of a word in the job title.
+
+Examples:
+* `findByEmploymentType Part-Time` returns all part-time employees.
+* `findByEmploymentType part` returns all part-time employees.
+* `findByEmploymentType Full-Time` returns all full-time employees (e.g shown below).
+* `findByEmploymentType ful` returns all full-time employees.
+
+
### Deleting a person : `delete`
@@ -140,7 +262,23 @@ Format: `delete INDEX`
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.
+* `findByDepartment Finance` followed by `delete 1` deletes the 1st person in the results of the `find` command.
+
+### Adding a note : `note`
+
+Adds a note to the specified person from the address book.
+
+Format: `note INDEX [NOTE]`
+
+* Adds a note to the person at the specified `INDEX`. The index refers to the position of the person in the currently displayed list on the GUI. The index **must be a positive integer** 1, 2, 3, …
+* Square brackets [ ] represent optional fields.
+* `NOTE` can be any string input.
+* Existing note value will be updated to the input value.
+* If the input is an empty string, the note will be reset.
+ `note 1`
+
+Examples:
+* `note 1 they/them`
### Clearing all entries : `clear`
@@ -156,14 +294,14 @@ Format: `exit`
### Saving the data
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+HRelper data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
### Editing the data file
-AddressBook data are saved automatically as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
+HRelper data are saved automatically as a JSON file `[JAR file location]/data/hrelper.json`. Advanced users are welcome to update data directly by editing that data file.
:exclamation: **Caution:**
-If your changes to the data file makes its format invalid, AddressBook will discard all data and start with an empty data file at the next run. Hence, it is recommended to take a backup of the file before editing it.
+If your changes to the data file makes its format invalid, HRelper will discard all data and start with an empty data file at the next run. Hence, it is recommended to take a backup of the file before editing it.
Furthermore, certain edits can cause the AddressBook to behave in unexpected ways (e.g., if a value entered is outside of the acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly.
@@ -175,15 +313,21 @@ _Details coming soon ..._
## 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.
+### Q1: What happens if I close the app? Will my data be lost?
+**A**: No worries! HRelper automatically saves all your data after every change. When you reopen the app, your latest data will still be there.
---------------------------------------------------------------------------------------------------------------------
+### Q2: Can I search for employees by job title or department?
+**A**: Yes! Use commands like `findByDepartment`, `findByJobTitle`, or `findByEmploymentType`.
+Example: `findByDepartment Marketing` will show all employees in the Marketing department.
+
+--------------------------------------------------------------------------------------------------------------------
## Known issues
1. **When using multiple screens**, if you move the application to a secondary screen, and later switch to using only the primary screen, the GUI will open off-screen. The remedy is to delete the `preferences.json` file created by the application before running the application again.
2. **If you minimize the Help Window** and then run the `help` command (or use the `Help` menu, or the keyboard shortcut `F1`) again, the original Help Window will remain minimized, and no new Help Window will appear. The remedy is to manually restore the minimized Help Window.
+3. HRelper currently does not validate whether email addresses are real, allowing users to input non-existent or invalid emails.
+4. HRelper does not currently verify the authenticity of user-provided addresses, which may result in the submission of inaccurate or non-existent locations.
--------------------------------------------------------------------------------------------------------------------
@@ -191,10 +335,54 @@ _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`
+**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL ic/NRIC g/GENDER d/DOB j/DATE OF JOINING nat/NATIONALITY a/ADDRESS/POSTAL CODE t/DEPARTMENT/EMPLOYMENTTYPE/JOBTITLE` e.g., `add n/John Doe p/98765432 e/johnd@example.com ic/T0312345A g/Male d/02-Jan-2001 j/15-Apr-2025 nat/Singaporean a/311, Clementi Ave 2, #02-25/119278 t/Finance/Full-Time/Financial Analyst`
**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`
+**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [g/GENDER] [d/DOB] [j/DATE OF JOINING] [nat/NATIONALITY] [a/ADDRESS/POSTAL CODE] [t/DEPARTMENT/EMPLOYMENT TYPE/JOBTITLE]` e.g.,`edit 2 n/James Lee e/jameslee@example.com`
+**Find by Department** | `findByDepartment KEYWORD` e.g., `findByDepartment HR`, `findByDepartment Fin`, `findByDepartment Information Technology` |
+**Find by Job Title** | `findByJobTitle KEYWORD` e.g., `findByJobTitle Engineer`, `findByJobTitle Dev`, `findByJobTitle Coordinator` |
+**Find by Employment Type** | `findByEmploymentType EMPLOYMENT_TYPE` e.g., `findByEmploymentType Full-Time`, `findByEmploymentType Contract` |
+**Note** | `note INDEX NOTE` e.g. note 1 he likes aadvarks
**List** | `list`
**Help** | `help`
+**View** | `view FULLNAME` `view PARTIALNAME` e.g., `view Alex Yeoh` or `view Yeoh`
+
+## Valid Departments, Employment Types, Job Titles of HRelper
+
+Here are the valid inputs for the respective fields in this particular working prototype.
+*Companies should customise such fields to fit their own business needs
+
+Fields | Valid Inputs
+--------|------------------
+**Departments** |`Human Resources`, `Finance`, `Accounting`, `Marketing`, `Sales`, `Customer Service`, `Information Technology`, `Research and Development`, `Operations`, `Legal`, `Supply Chain & Logistics`, `Procurement & Purchasing`, `Engineering`, `Quality Assurance`, `Product Management`, `Manufacturing`, `Public Relations`, `Corporate Communications`, `Compliance & Risk Management`, `Business Development`, `Data Science`, `Cybersecurity`, `Software Development`, `UX/UI Design`, `Artificial Intelligence & Machine Learning`, `Training & Development`, `Facilities Management`, `Administration`, `Health & Safety`, `Diversity, Equity & Inclusion`
+**Employment Types** |`Full-Time`, `Part-Time`, `Contract`, `Temporary`, `Internship`, `Freelance`, `Apprenticeship`, `Remote`, `Hybrid`
+**Job Titles** | `Software Engineer`, `Data Analyst`, `Product Manager`, `HR Coordinator`, `Marketing Specialist`, `Sales Associate`, `Financial Analyst`, `Operations Manager`, `UX Designer`, `Project Manager`, `Business Consultant`, `Mechanical Engineer`, `Graphic Designer`, `Customer Support Representative`, `IT Technician`, `Electrical Engineer`, `Legal Advisor`, `Healthcare Administrator`, `Content Writer`, `Cybersecurity Analyst`, `Network Engineer`, `Quality Assurance Tester`, `Recruitment Specialist`, `Social Media Manager`, `Supply Chain Manager`
+**Nationalities** |`Afghan`, `Albanian`, `Algerian`, `American`, `Andorran`, `Angolan`, `Argentine`,`Armenian`, `Australian`, `Austrian`, `Azerbaijani`, `Bahamian`, `Bahraini`,`Bangladeshi`, `Barbadian`, `Belarusian`, `Belgian`, `Belizean`, `Beninese`,`Bhutanese`, `Bolivian`, `Bosnian`, `Botswanan`, `Brazilian`, `British`,`Bruneian`, `Bulgarian`, `Burkinabé`, `Burmese`, `Burundian`, `Cambodian`, `Cameroonian`, `Canadian`, `Cape Verdean`, `Central African`, `Chadian`,`Chilean`, `Chinese`, `Colombian`, `Comorian`, `Congolese`, `Costa Rican`,`Croatian`, `Cuban`, `Cypriot`, `Czech`, `Danish`, `Djiboutian`, `Dominican`,`Dutch`, `Ecuadorian`, `Egyptian`, `Emirati`, `Equatorial Guinean`,`Eritrean`, `Estonian`, `Ethiopian`, `Fijian`, `Filipino`, `Finnish`, `French`,`Gabonese`, `Gambian`, `Georgian`, `German`, `Ghanaian`, `Greek`, `Grenadian`,`Guatemalan`, `Guinean`, `Guyanese`, `Haitian`, `Honduran`, `Hungarian`,`Icelandic`, `Indian`, `Indonesian`, `Iranian`, `Iraqi`, `Irish`, `Israeli`,`Italian`, `Ivorian`, `Jamaican`, `Japanese`, `Jordanian`, `Kazakh`, `Kenyan`,`Kiribati`, `Kuwaiti`, `Kyrgyz`, `Laotian`, `Latvian`, `Lebanese`, `Liberian`,`Libyan`, `Liechtenstein`, `Lithuanian`, `Luxembourgish`, `Malagasy`, `Malawian`,`Malaysian`, `Maldivian`, `Malian`, `Maltese`, `Marshallese`, `Mauritanian`,`Mauritian`, `Mexican`, `Micronesian`, `Moldovan`, `Monacan`, `Mongolian`,`Montenegrin`, `Moroccan`, `Mozambican`, `Namibian`, `Nauruan`, `Nepalese`,`New Zealander`, `Nicaraguan`, `Nigerien`, `Nigerian`, `North Korean`,`North Macedonian`, `Norwegian`, `Omani`, `Pakistani`, `Palauan`, `Palestinian`,`Panamanian`, `Papua New Guinean`, `Paraguayan`, `Peruvian`, `Polish`, `Portuguese`,`Qatari`, `Romanian`, `Russian`, `Rwandan`, `Saint Lucian`, `Salvadoran`, `Samoan`,`Saudi Arabian`, `Scottish`, `Senegalese`, `Serbian`, `Seychellois`, `Sierra Leonean`,`Singaporean`, `Slovak`, `Slovenian`, `Solomon Islander`, `Somali`, `South African`,`South Korean`, `South Sudanese`, `Spanish`, `Sri Lankan`, `Sudanese`, `Surinamese`,`Swazi`, `Swedish`, `Swiss`, `Syrian`, `Tajik`, `Tanzanian`, `Thai`, `Timorese`,`Togolese`, `Tongan`, `Trinidadian`, `Tunisian`, `Turkish`, `Turkmen`, `Tuvaluan`,`Ugandan`, `Ukrainian`, `Uruguayan`, `Uzbek`, `Vanuatuan`, `Venezuelan`, `Vietnamese`,`Welsh`, `Yemeni`, `Zambian`, `Zimbabwean`, `Other`
+# Valid Short-Forms of HRelper
+
+Please refer to the table for some valid short-form `department` tag inputs. The `department` to `short-form name` mapping is as follows
+
+| Department Name | Short-form |
+|------------------------------------------------|-----------|
+| **Human resources** | `HR` |
+| **Customer Service** | `CS` |
+| **Information Technology** | `IT` |
+| **Research and Development** | `R&D` |
+| **Supply Chain & Logistics** | `SCM` |
+| **Procurement & Purchasing** | `Procurement` |
+| **Quality Assurance** | `QA` |
+| **Product Management** | `PR` |
+| **Corporate Communications** | `CorpComm`|
+| **Business Development** | `BizDev` |
+| **Data Science** | `DS` |
+| **Cybersecurity** | `CyberSec` |
+| **Software Development** | `SD` |
+| **UX/UI Design** | `UX&UI` |
+| **Artificial Intelligence & Machine Learning** | `AI&ML` |
+| **Training & Development** | `T&D` |
+| **Facilities Management** | `FM` |
+| **Health & Safety** | `H&S` |
+| **Diversity, Equity & Inclusion** | `DEI` |
+
+Note: `Finance` `Accounting` `Marketing` `Sales` `Operations` `Legal` `Engineering`
+`Manufacturing` `Public Relations` `Administration` tags do not have valid short-forms
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..ad5797d7638 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,4 +1,4 @@
-title: "AB-3"
+title: "HRelper"
theme: minima
header_pages:
@@ -8,7 +8,7 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "AY2425S2-CS2103T-F14-2/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..63dd2bcadc3 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: "HRelper";
font-size: 32px;
}
}
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
index 598474a5c82..b1d5ffb026d 100644
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ b/docs/diagrams/BetterModelClassDiagram.puml
@@ -12,10 +12,18 @@ UniqueTagList -[hidden]down- UniquePersonList
UniqueTagList -right-> "*" Tag
UniquePersonList -right-> Person
-Person -up-> "*" Tag
+Person -up-> "1" Tag
+Tag *-up-> Department
+Tag *-up-> EmploymentType
+Tag *-up-> JobTitle
Person *--> Name
Person *--> Phone
Person *--> Email
+Person *--> Nric
+Person *--> Dob
+Person *--> DateOfJoining
+Person *--> Nationality
+Person *--> Gender
Person *--> Address
@enduml
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 0de5673070d..eec56e7a1d4 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 as ModelPackage <>{
+Package "Model" as ModelPackage <>{
Class "<>\nReadOnlyAddressBook" as ReadOnlyAddressBook
Class "<>\nReadOnlyUserPrefs" as ReadOnlyUserPrefs
Class "<>\nModel" as Model
@@ -16,11 +16,20 @@ Class UniquePersonList
Class Person
Class Address
Class Email
+Class Nric
+Class Gender
+Class Dob
+Class DateOfJoining
+Class Nationality
Class Name
Class Phone
Class Tag
+Class Department
+Class EmploymentType
+Class JobTitle
Class I #FFFFFF
+Class I2 #FFFFFF
}
Class HiddenOutside #FFFFFF
@@ -40,8 +49,18 @@ UniquePersonList --> "~* all" Person
Person *--> Name
Person *--> Phone
Person *--> Email
+Person *--> Nric
+Person *--> Gender
+Person *--> Dob
+Person *--> DateOfJoining
+Person *--> Nationality
Person *--> Address
-Person *--> "*" Tag
+Person *--> Tag
+
+'Force Tag Department
+Tag *-down-> Department
+Tag *-down-> EmploymentType
+Tag *-down-> JobTitle
Person -[hidden]up--> I
UniquePersonList -[hidden]right-> I
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 95473d5aa19..4108c7790b7 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -1,7 +1,7 @@
@startuml
!include style.puml
-skinparam arrowThickness 1.1
-skinparam arrowColor UI_COLOR_T4
+skinparam arrowThickness 1.2
+skinparam arrowColor UI_COLOR_T3
skinparam classBackgroundColor UI_COLOR
package UI <>{
diff --git a/docs/images/AfterHome.png b/docs/images/AfterHome.png
new file mode 100644
index 00000000000..15f8e84ffe7
Binary files /dev/null and b/docs/images/AfterHome.png differ
diff --git a/docs/images/BeforeHome.png b/docs/images/BeforeHome.png
new file mode 100644
index 00000000000..5a647b762e5
Binary files /dev/null and b/docs/images/BeforeHome.png differ
diff --git a/docs/images/BetterModelClassDiagram-1.png b/docs/images/BetterModelClassDiagram-1.png
new file mode 100644
index 00000000000..2c333daa6a9
Binary files /dev/null and b/docs/images/BetterModelClassDiagram-1.png differ
diff --git a/docs/images/FilterImage.png b/docs/images/FilterImage.png
new file mode 100644
index 00000000000..158a34993c3
Binary files /dev/null and b/docs/images/FilterImage.png differ
diff --git a/docs/images/IntroPic.png b/docs/images/IntroPic.png
new file mode 100644
index 00000000000..b874cb9bd28
Binary files /dev/null and b/docs/images/IntroPic.png differ
diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png
index a19fb1b4ac8..a1ec4c977e7 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 5bd77847aa2..077521dc96f 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/ViewImage.png b/docs/images/ViewImage.png
new file mode 100644
index 00000000000..c54fddbee46
Binary files /dev/null and b/docs/images/ViewImage.png differ
diff --git a/docs/images/chen-xiangrui.png b/docs/images/chen-xiangrui.png
new file mode 100644
index 00000000000..df1042863ea
Binary files /dev/null and b/docs/images/chen-xiangrui.png differ
diff --git a/docs/images/chenxy12345.png b/docs/images/chenxy12345.png
new file mode 100644
index 00000000000..373967c1513
Binary files /dev/null and b/docs/images/chenxy12345.png differ
diff --git a/docs/images/davidfoo07.png b/docs/images/davidfoo07.png
new file mode 100644
index 00000000000..f24edbaacf7
Binary files /dev/null and b/docs/images/davidfoo07.png differ
diff --git a/docs/images/findAlexDavidResult.png b/docs/images/findAlexDavidResult.png
deleted file mode 100644
index 235da1c273e..00000000000
Binary files a/docs/images/findAlexDavidResult.png and /dev/null differ
diff --git a/docs/images/findByEmploymentType.png b/docs/images/findByEmploymentType.png
new file mode 100644
index 00000000000..afa6c1d91d9
Binary files /dev/null and b/docs/images/findByEmploymentType.png differ
diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png
index b1f70470137..b75363bc77f 100644
Binary files a/docs/images/helpMessage.png and b/docs/images/helpMessage.png differ
diff --git a/docs/images/johndoe.png b/docs/images/johndoe.png
deleted file mode 100644
index 1ce7ce16dc8..00000000000
Binary files a/docs/images/johndoe.png and /dev/null differ
diff --git a/docs/images/wj200.png b/docs/images/wj200.png
new file mode 100644
index 00000000000..5dcc7f81348
Binary files /dev/null and b/docs/images/wj200.png differ
diff --git a/docs/images/wyongqiing.png b/docs/images/wyongqiing.png
new file mode 100644
index 00000000000..9c6862510b1
Binary files /dev/null and b/docs/images/wyongqiing.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..1e407c23bc7 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,17 +1,17 @@
---
layout: page
-title: AddressBook Level-3
+title: HRelper
---
-[](https://github.com/se-edu/addressbook-level3/actions)
-[](https://codecov.io/gh/se-edu/addressbook-level3)
+[](https://github.com/AY2425S2-CS2103T-F14-2/tp/actions)
+[](https://codecov.io/gh/AY2425S2-CS2103T-F14-2/tp)
-
+
-**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).
+**HRelper** is a desktop Human Resource (HR) management application designed to streamline the way users manage employee contact and profile details. Built for efficiency and speed, HRelper combines the familiarity of a Graphical User Interface (GUI) with the power and precision of a Command Line Interface (CLI).
-* 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 HRelper, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
+* If you are interested about developing HRelper, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java
index 678ddc8c218..65b5540e79a 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/address/MainApp.java
@@ -36,7 +36,7 @@
*/
public class MainApp extends Application {
- public static final Version VERSION = new Version(0, 2, 2, true);
+ public static final Version VERSION = new Version(1, 3, 0, true);
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
@@ -48,7 +48,7 @@ public class MainApp extends Application {
@Override
public void init() throws Exception {
- logger.info("=============================[ Initializing AddressBook ]===========================");
+ logger.info("=============================[ Initializing HRelper ]===========================");
super.init();
AppParameters appParameters = AppParameters.parse(getParameters());
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java
index 92cd8fa605a..3265121b621 100644
--- a/src/main/java/seedu/address/logic/Logic.java
+++ b/src/main/java/seedu/address/logic/Logic.java
@@ -47,4 +47,6 @@ public interface Logic {
* Set the user prefs' GUI settings.
*/
void setGuiSettings(GuiSettings guiSettings);
+
+ void showAllPersons();
}
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java
index 5aa3b91c7d0..924abd47b63 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/address/logic/LogicManager.java
@@ -85,4 +85,10 @@ public GuiSettings getGuiSettings() {
public void setGuiSettings(GuiSettings guiSettings) {
model.setGuiSettings(guiSettings);
}
+
+ @Override
+ public void showAllPersons() {
+ model.updateFilteredPersonList(person -> true);
+ }
+
}
diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java
index ecd32c31b53..aa0df0768a1 100644
--- a/src/main/java/seedu/address/logic/Messages.java
+++ b/src/main/java/seedu/address/logic/Messages.java
@@ -16,6 +16,11 @@ public class Messages {
public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
+
+ public static final String MESSAGE_PROFILE_FOUND = "Profile found: %1$s";
+
+ public static final String MESSAGE_PROFILE_NOT_FOUND = "No matching profile found!!";
+
public static final String MESSAGE_DUPLICATE_FIELDS =
"Multiple values specified for the following single-valued field(s): ";
@@ -41,10 +46,18 @@ public static String format(Person person) {
.append(person.getPhone())
.append("; Email: ")
.append(person.getEmail())
+ .append("; Gender: ")
+ .append(person.getGender())
+ .append("; Dob: ")
+ .append(person.getDob())
+ .append("; DateOfJoining: ")
+ .append(person.getDateOfJoining())
+ .append("; Nationality: ")
+ .append(person.getNationality())
.append("; Address: ")
.append(person.getAddress())
- .append("; Tags: ");
- person.getTags().forEach(builder::append);
+ .append("; Tags: ")
+ .append(person.getTag());
return builder.toString();
}
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
index 5d7185a9680..03aec913bea 100644
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ b/src/main/java/seedu/address/logic/commands/AddCommand.java
@@ -2,11 +2,21 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DOB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GENDER;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NATIONALITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NRIC;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
@@ -25,15 +35,25 @@ public class AddCommand extends Command {
+ PREFIX_NAME + "NAME "
+ PREFIX_PHONE + "PHONE "
+ PREFIX_EMAIL + "EMAIL "
- + PREFIX_ADDRESS + "ADDRESS "
+ + PREFIX_NRIC + "NRIC "
+ + PREFIX_GENDER + "GENDER "
+ + PREFIX_DOB + "DOB "
+ + PREFIX_DATE + "DATE OF JOINING "
+ + PREFIX_NATIONALITY + "NATIONALITY "
+ + PREFIX_ADDRESS + "ADDRESS/POSTAL CODE "
+ "[" + PREFIX_TAG + "TAG]...\n"
+ "Example: " + COMMAND_WORD + " "
+ PREFIX_NAME + "John Doe "
+ PREFIX_PHONE + "98765432 "
+ PREFIX_EMAIL + "johnd@example.com "
- + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
- + PREFIX_TAG + "friends "
- + PREFIX_TAG + "owesMoney";
+ + PREFIX_NRIC + "T0312345A "
+ + PREFIX_GENDER + "Male "
+ + PREFIX_DOB + "02-Jan-2001 "
+ + PREFIX_DATE + "15-Apr-2025 "
+ + PREFIX_NATIONALITY + "Singaporean "
+ + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25/119780 "
+ + PREFIX_TAG + "Finance/Full-Time/Financial Analyst\n\n"
+ + "Command to follow: add n/ p/ e/ ic/ g/ d/ j/ nat/ a/ t/// ";
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";
@@ -56,10 +76,35 @@ public CommandResult execute(Model model) throws CommandException {
throw new CommandException(MESSAGE_DUPLICATE_PERSON);
}
+ // Add the validation for date of birth vs date of joining
+ if (!isDateOfJoiningValid(toAdd.getDob().value, toAdd.getDateOfJoining().value)) {
+ throw new CommandException("Date of joining cannot be earlier than date of birth.");
+ }
+
model.addPerson(toAdd);
return new CommandResult(String.format(MESSAGE_SUCCESS, Messages.format(toAdd)));
}
+ /**
+ * Checks if the date of joining is valid (not earlier than date of birth)
+ * @param dobString Date of birth in dd-MMM-yyyy format
+ * @param dojString Date of joining in dd-MMM-yyyy format
+ * @return true if date of joining is valid, false otherwise
+ */
+ private boolean isDateOfJoiningValid(String dobString, String dojString) {
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy", Locale.ENGLISH);
+ Date dob = sdf.parse(dobString);
+ Date doj = sdf.parse(dojString);
+
+ // Check if date of joining is on or after date of birth
+ return !doj.before(dob);
+ } catch (ParseException e) {
+ // This shouldn't happen since we've already validated the format
+ return false;
+ }
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/address/logic/commands/CommandResult.java
index 249b6072d0d..42ffc8fda74 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/address/logic/commands/CommandResult.java
@@ -19,13 +19,16 @@ public class CommandResult {
/** The application should exit. */
private final boolean exit;
+ private final boolean isHome;
+
/**
* 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 isHome) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
this.exit = exit;
+ this.isHome = isHome;
}
/**
@@ -33,7 +36,7 @@ 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);
}
public String getFeedbackToUser() {
@@ -48,6 +51,10 @@ public boolean isExit() {
return exit;
}
+ public boolean isHome() {
+ return isHome;
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -62,12 +69,13 @@ public boolean equals(Object other) {
CommandResult otherCommandResult = (CommandResult) other;
return feedbackToUser.equals(otherCommandResult.feedbackToUser)
&& showHelp == otherCommandResult.showHelp
- && exit == otherCommandResult.exit;
+ && exit == otherCommandResult.exit
+ && isHome == otherCommandResult.isHome;
}
@Override
public int hashCode() {
- return Objects.hash(feedbackToUser, showHelp, exit);
+ return Objects.hash(feedbackToUser, showHelp, exit, isHome);
}
@Override
@@ -76,6 +84,7 @@ public String toString() {
.add("feedbackToUser", feedbackToUser)
.add("showHelp", showHelp)
.add("exit", exit)
+ .add("isHome", isHome)
.toString();
}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
index 4b581c7331e..cc1a074d900 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/seedu/address/logic/commands/EditCommand.java
@@ -2,18 +2,19 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DOB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GENDER;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NATIONALITY;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-import java.util.Collections;
-import java.util.HashSet;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.Set;
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.CollectionUtil;
@@ -22,10 +23,17 @@
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.person.Address;
+import seedu.address.model.person.DateOfJoining;
+import seedu.address.model.person.Dob;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Gender;
import seedu.address.model.person.Name;
+import seedu.address.model.person.Nationality;
+import seedu.address.model.person.Note;
+import seedu.address.model.person.Nric;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.person.ProfileContainsKeywordsPredicate;
import seedu.address.model.tag.Tag;
/**
@@ -42,8 +50,12 @@ public class EditCommand extends Command {
+ "[" + PREFIX_NAME + "NAME] "
+ "[" + PREFIX_PHONE + "PHONE] "
+ "[" + PREFIX_EMAIL + "EMAIL] "
+ + "[" + PREFIX_GENDER + "GENDER] "
+ + "[" + PREFIX_DOB + "DOB] "
+ + "[" + PREFIX_DATE + "DATE OF JOINING] "
+ + "[" + PREFIX_NATIONALITY + "NATIONALITY] "
+ "[" + PREFIX_ADDRESS + "ADDRESS] "
- + "[" + PREFIX_TAG + "TAG]...\n"
+ + "[" + PREFIX_TAG + "DEPARTMENT/EMPLOYMENT TYPE/JOB TITLE]\n"
+ "Example: " + COMMAND_WORD + " 1 "
+ PREFIX_PHONE + "91234567 "
+ PREFIX_EMAIL + "johndoe@example.com";
@@ -51,6 +63,9 @@ public class EditCommand extends Command {
public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s";
public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book.";
+ public static final String MESSAGE_NOT_CHANGED = "The field(s) provided to edit is already present.";
+
+ private ProfileContainsKeywordsPredicate predicate;
private final Index index;
private final EditPersonDescriptor editPersonDescriptor;
@@ -76,15 +91,24 @@ public CommandResult execute(Model model) throws CommandException {
throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
}
+ if (!editPersonDescriptor.isAnyFieldEdited()) {
+ throw new CommandException(EditCommand.MESSAGE_NOT_EDITED);
+ }
+
Person personToEdit = lastShownList.get(index.getZeroBased());
Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
+ this.predicate = new ProfileContainsKeywordsPredicate(Arrays.asList(editedPerson.getName().toString()));
if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
throw new CommandException(MESSAGE_DUPLICATE_PERSON);
}
+ if (personToEdit.equals(editedPerson)) {
+ throw new CommandException(MESSAGE_NOT_CHANGED);
+ }
+
model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.updateFilteredPersonList(predicate);
return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson)));
}
@@ -92,16 +116,28 @@ public CommandResult execute(Model model) throws CommandException {
* Creates and returns a {@code Person} with the details of {@code personToEdit}
* edited with {@code editPersonDescriptor}.
*/
- private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
+ private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor)
+ throws CommandException {
assert personToEdit != null;
Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName());
Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone());
Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail());
+ Nric updatedNric = personToEdit.getNric();
+ Gender updatedGender = editPersonDescriptor.getGender().orElse(personToEdit.getGender());
+ Dob updatedDob = editPersonDescriptor.getDob().orElse(personToEdit.getDob());
+ DateOfJoining updatedDate = editPersonDescriptor.getDateOfJoining().orElse(personToEdit.getDateOfJoining());
+ Nationality updatedNationality = editPersonDescriptor.getNationality().orElse(personToEdit.getNationality());
Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
- Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
+ Tag updatedTag = editPersonDescriptor.getTag().orElse(personToEdit.getTag());
+ Note updatedNote = editPersonDescriptor.getNote().orElse(personToEdit.getNote());
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
+ if (!updatedDate.toLocalDate().isAfter(updatedDob.toLocalDate())) {
+ throw new CommandException("Date of Joining must be after DOB.");
+ }
+
+ return new Person(updatedName, updatedPhone, updatedEmail, updatedNric, updatedGender, updatedDob, updatedDate,
+ updatedNationality, updatedAddress, updatedNote, updatedTag);
}
@Override
@@ -136,8 +172,13 @@ public static class EditPersonDescriptor {
private Name name;
private Phone phone;
private Email email;
+ private Gender gender;
+ private Dob dob;
+ private DateOfJoining dateOfJoining;
+ private Nationality nationality;
private Address address;
- private Set tags;
+ private Note note;
+ private Tag tag;
public EditPersonDescriptor() {}
@@ -149,15 +190,21 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) {
setName(toCopy.name);
setPhone(toCopy.phone);
setEmail(toCopy.email);
+ setGender(toCopy.gender);
+ setDob(toCopy.dob);
+ setDateOfJoining(toCopy.dateOfJoining);
+ setNationality(toCopy.nationality);
setAddress(toCopy.address);
- setTags(toCopy.tags);
+ setNote(toCopy.note);
+ setTag(toCopy.tag);
}
/**
* Returns true if at least one field is edited.
*/
public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
+ return CollectionUtil.isAnyNonNull(name, phone, email, gender, dob, dateOfJoining,
+ nationality, address, tag);
}
public void setName(Name name) {
@@ -184,6 +231,38 @@ public Optional getEmail() {
return Optional.ofNullable(email);
}
+ public void setGender(Gender gender) {
+ this.gender = gender;
+ }
+
+ public Optional getGender() {
+ return Optional.ofNullable(gender);
+ }
+
+ public void setDob(Dob dob) {
+ this.dob = dob;
+ }
+
+ public Optional getDob() {
+ return Optional.ofNullable(dob);
+ }
+
+ public void setDateOfJoining(DateOfJoining dateOfJoining) {
+ this.dateOfJoining = dateOfJoining;
+ }
+
+ public Optional getDateOfJoining() {
+ return Optional.ofNullable(dateOfJoining);
+ }
+
+ public void setNationality(Nationality nationality) {
+ this.nationality = nationality;
+ }
+
+ public Optional getNationality() {
+ return Optional.ofNullable(nationality);
+ }
+
public void setAddress(Address address) {
this.address = address;
}
@@ -192,25 +271,26 @@ public Optional getAddress() {
return Optional.ofNullable(address);
}
- /**
- * Sets {@code tags} to this object's {@code tags}.
- * A defensive copy of {@code tags} is used internally.
- */
- public void setTags(Set tags) {
- this.tags = (tags != null) ? new HashSet<>(tags) : null;
+ public void setNote(Note note) {
+ this.note = note;
}
- /**
- * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- * Returns {@code Optional#empty()} if {@code tags} is null.
- */
- public Optional> getTags() {
- return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
+ public Optional getNote() {
+ return Optional.ofNullable(note);
+ }
+
+ public void setTag(Tag tag) {
+ this.tag = tag;
}
+ public Optional getTag() {
+ return Optional.ofNullable(tag);
+ }
+
+
@Override
public boolean equals(Object other) {
+
if (other == this) {
return true;
}
@@ -224,8 +304,13 @@ public boolean equals(Object other) {
return Objects.equals(name, otherEditPersonDescriptor.name)
&& Objects.equals(phone, otherEditPersonDescriptor.phone)
&& Objects.equals(email, otherEditPersonDescriptor.email)
+ && Objects.equals(gender, otherEditPersonDescriptor.gender)
+ && Objects.equals(dob, otherEditPersonDescriptor.dob)
+ && Objects.equals(dateOfJoining, otherEditPersonDescriptor.dateOfJoining)
+ && Objects.equals(nationality, otherEditPersonDescriptor.nationality)
&& Objects.equals(address, otherEditPersonDescriptor.address)
- && Objects.equals(tags, otherEditPersonDescriptor.tags);
+ && Objects.equals(note, otherEditPersonDescriptor.note)
+ && Objects.equals(tag, otherEditPersonDescriptor.tag);
}
@Override
@@ -234,8 +319,13 @@ public String toString() {
.add("name", name)
.add("phone", phone)
.add("email", email)
+ .add("gender", gender)
+ .add("dob", dob)
+ .add("dateOfJoining", dateOfJoining)
+ .add("nationality", nationality)
.add("address", address)
- .add("tags", tags)
+ .add("note", note)
+ .add("tag", tag)
.toString();
}
}
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java
index 3dd85a8ba90..acac9a21374 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java
@@ -13,7 +13,7 @@ public class ExitCommand extends Command {
@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/FindByDepartmentCommand.java b/src/main/java/seedu/address/logic/commands/FindByDepartmentCommand.java
new file mode 100644
index 00000000000..1929b966a16
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindByDepartmentCommand.java
@@ -0,0 +1,47 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.person.DepartmentContainsKeywordPredicate;
+
+/**
+ * Finds and lists all persons in address book whose department contains the specified keyword.
+ */
+public class FindByDepartmentCommand extends Command {
+
+ public static final String COMMAND_WORD = "findByDepartment";
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Finds all persons whose department contains the specified keyword.\n"
+ + "Parameters: DEPARTMENT_KEYWORD\n"
+ + "Example: " + COMMAND_WORD + " HR";
+
+ private final DepartmentContainsKeywordPredicate predicate;
+
+ public FindByDepartmentCommand(DepartmentContainsKeywordPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof FindByDepartmentCommand)) {
+ return false;
+ }
+
+ FindByDepartmentCommand otherFindCommand = (FindByDepartmentCommand) other;
+ return predicate.equals(otherFindCommand.predicate);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindByEmploymentTypeCommand.java b/src/main/java/seedu/address/logic/commands/FindByEmploymentTypeCommand.java
new file mode 100644
index 00000000000..c0d89198df6
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindByEmploymentTypeCommand.java
@@ -0,0 +1,47 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.person.EmploymentTypeContainsKeywordPredicate;
+
+/**
+ * Finds and lists all persons in address book whose department contains the specified keyword.
+ */
+public class FindByEmploymentTypeCommand extends Command {
+
+ public static final String COMMAND_WORD = "findByEmploymentType";
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Finds all persons whose department contains the specified keyword.\n"
+ + "Parameters: EMPLOYMENTTYPE_KEYWORD\n"
+ + "Example: " + COMMAND_WORD + " Full-time";
+
+ private final EmploymentTypeContainsKeywordPredicate predicate;
+
+ public FindByEmploymentTypeCommand(EmploymentTypeContainsKeywordPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof FindByEmploymentTypeCommand)) {
+ return false;
+ }
+
+ FindByEmploymentTypeCommand otherFindCommand = (FindByEmploymentTypeCommand) other;
+ return predicate.equals(otherFindCommand.predicate);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindByJobTitleCommand.java b/src/main/java/seedu/address/logic/commands/FindByJobTitleCommand.java
new file mode 100644
index 00000000000..6f8ecf8b433
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindByJobTitleCommand.java
@@ -0,0 +1,61 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.person.JobTitleContainsKeywordPredicate;
+
+/**
+ * Finds and lists all persons in address book whose department contains the specified keyword.
+ */
+public class FindByJobTitleCommand extends Command {
+
+ public static final String COMMAND_WORD = "findByJobTitle";
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Finds all persons whose job title matches the specified keyword.\n"
+ + "The search is case-insensitive and supports:\n"
+ + "- Exact job title matching\n"
+ + "- Partial matching with at least 3 consecutive letters\n"
+ + "Parameters: JOBTITLE_KEYWORD\n"
+ + "Examples:\n"
+ + "- " + COMMAND_WORD + " Engineer (finds all Engineers)\n"
+ + "- " + COMMAND_WORD + " Dev (finds all Developers with 'Dev' in their title)\n"
+ + "- " + COMMAND_WORD + " Coord (finds all Coordinators)";
+
+ public static final String MESSAGE_JOBTITLE_CONSTRAINTS = "Job title search terms should only contain alphabetic "
+ + "characters and spaces. It should not be blank.\n"
+ + "Search terms must be at least 3 characters long for partial matching.\n"
+ + "Examples:\n"
+ + "- Engineer\n"
+ + "- Dev (matches Developer)\n"
+ + "- Coord (matches Coordinator)";
+
+ private final JobTitleContainsKeywordPredicate predicate;
+
+ public FindByJobTitleCommand(JobTitleContainsKeywordPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof FindByJobTitleCommand)) {
+ return false;
+ }
+
+ FindByJobTitleCommand otherFindCommand = (FindByJobTitleCommand) other;
+ return predicate.equals(otherFindCommand.predicate);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
index 72b9eddd3a7..5786eb45a34 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindCommand.java
@@ -1,58 +1,30 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import seedu.address.commons.util.ToStringBuilder;
-import seedu.address.logic.Messages;
import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
/**
- * Finds and lists all persons in address book whose name contains any of the argument keywords.
- * Keyword matching is case insensitive.
+ * Command to display an error message when an invalid 'find' command is used,
+ * and suggest alternative search commands.
*/
public class FindCommand extends Command {
public static final String COMMAND_WORD = "find";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
- + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
- + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
- + "Example: " + COMMAND_WORD + " alice bob charlie";
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows error message that this command is invalid. "
+ + "Use 'findByDepartment', 'findByEmploymentType',"
+ + "or 'findByJobTitle' to search with the specified criteria.\n"
+ + "Example: " + COMMAND_WORD;
- private final NameContainsKeywordsPredicate predicate;
-
- public FindCommand(NameContainsKeywordsPredicate predicate) {
- this.predicate = predicate;
- }
+ public static final String ERROR_MESSAGE = "Try using 'findByDepartment', "
+ + "'findByEmploymentType', or 'findByJobTitle' instead.";
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.updateFilteredPersonList(predicate);
- return new CommandResult(
- String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof FindCommand)) {
- return false;
- }
-
- FindCommand otherFindCommand = (FindCommand) other;
- return predicate.equals(otherFindCommand.predicate);
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this)
- .add("predicate", predicate)
- .toString();
+ // Output invalid command message and suggest alternatives
+ return new CommandResult(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ERROR_MESSAGE));
}
}
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java
index bf824f91bd0..07d26e2a23c 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java
@@ -16,6 +16,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/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
index 84be6ad2596..f9f974a6b85 100644
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ListCommand.java
@@ -19,6 +19,10 @@ public class ListCommand extends Command {
public CommandResult execute(Model model) {
requireNonNull(model);
model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(MESSAGE_SUCCESS);
+ if (model.getFilteredPersonList().size() == 0) {
+ return new CommandResult("No persons in the database currently.");
+ } else {
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
}
}
diff --git a/src/main/java/seedu/address/logic/commands/NoteCommand.java b/src/main/java/seedu/address/logic/commands/NoteCommand.java
new file mode 100644
index 00000000000..33a8d3ca82e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/NoteCommand.java
@@ -0,0 +1,102 @@
+package seedu.address.logic.commands;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Arrays;
+import java.util.List;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Note;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.ProfileContainsKeywordsPredicate;
+
+
+/**
+ * Changes the remark of an existing person in the address book.
+ */
+
+
+public class NoteCommand extends Command {
+
+ public static final String COMMAND_WORD = "note";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the note of the person identified "
+ + "by the index number used in the last person listing. "
+ + "Existing note will be overwritten by the input.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "[NOTE]\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + "Likes to swim.";
+
+ public static final String MESSAGE_ADD_NOTE_SUCCESS = "Added note to Person: ";
+ public static final String MESSAGE_DELETE_NOTE_SUCCESS = "Note is empty now for Person: ";
+
+ private final Index index;
+ private ProfileContainsKeywordsPredicate predicate;
+ private final Note note;
+ /**
+ * @param index of the person in the filtered person list to edit the remark
+ * @param note of the person to be updated to
+ */
+ public NoteCommand(Index index, Note note) {
+ requireAllNonNull(index, note);
+ this.index = index;
+ this.note = note;
+ }
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ List lastShownList = model.getFilteredPersonList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToEdit = lastShownList.get(index.getZeroBased());
+ Person editedPerson = new Person(personToEdit.getName(), personToEdit.getPhone(),
+ personToEdit.getEmail(), personToEdit.getNric(),
+ personToEdit.getGender(), personToEdit.getDob(),
+ personToEdit.getDateOfJoining(),
+ personToEdit.getNationality(), personToEdit.getAddress(),
+ note, personToEdit.getTag());
+
+ this.predicate = new ProfileContainsKeywordsPredicate(Arrays.asList(editedPerson.getName().toString()));
+ model.setPerson(personToEdit, editedPerson);
+ model.updateFilteredPersonList(predicate);
+
+ return new CommandResult(generateSuccessMessage(editedPerson));
+ }
+
+ /**
+ * Generates a command execution success message based on whether the note is added to or removed from
+ * {@code personToEdit}.
+ */
+ private String generateSuccessMessage(Person personToEdit) {
+ if (note.equals(new Note(" "))
+ && !(personToEdit.getNote().value.isEmpty())) {
+ return MESSAGE_DELETE_NOTE_SUCCESS + " Name: " + personToEdit.getName().toString()
+ + " Nric: " + personToEdit.getNric().toString();
+ } else {
+ return MESSAGE_ADD_NOTE_SUCCESS + " Name: " + personToEdit.getName().toString()
+ + " Nric: " + personToEdit.getNric().toString() + " Note: " + note;
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof NoteCommand)) {
+ return false;
+ }
+
+ NoteCommand n = (NoteCommand) other;
+ return index.equals(n.index)
+ && note.equals(n.note);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ViewCommand.java b/src/main/java/seedu/address/logic/commands/ViewCommand.java
new file mode 100644
index 00000000000..72d8976048d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ViewCommand.java
@@ -0,0 +1,67 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.person.ProfileContainsKeywordsPredicate;
+
+/**
+ * View the person's profile
+ */
+public class ViewCommand extends Command {
+
+ public static final String COMMAND_WORD = "view";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Views the profile "
+ + "by the fullname. "
+ + "Existing profile will be shown.\n"
+ + "Parameters: FULLNAME\n"
+ + "Example: " + COMMAND_WORD + " Alex Tan";
+
+ private final ProfileContainsKeywordsPredicate predicate;
+
+ public ViewCommand(ProfileContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+ if (model.getFilteredPersonList().isEmpty()) {
+ return new CommandResult(Messages.MESSAGE_PROFILE_NOT_FOUND);
+ }
+
+ String names = model.getFilteredPersonList().stream()
+ .map(person -> person.getName().fullName)
+ .reduce((name1, name2) -> name1 + ", " + name2)
+ .orElse("");
+
+ return new CommandResult(String.format(Messages.MESSAGE_PROFILE_FOUND, names));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ViewCommand)) {
+ return false;
+ }
+
+ ViewCommand otherViewCommand = (ViewCommand) other;
+ return predicate.equals(otherViewCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("predicate", predicate)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
index 4ff1a97ed77..c1b01ce61bb 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
@@ -2,19 +2,29 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DOB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GENDER;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NATIONALITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NRIC;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import java.util.Set;
import java.util.stream.Stream;
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.Address;
+import seedu.address.model.person.DateOfJoining;
+import seedu.address.model.person.Dob;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Gender;
import seedu.address.model.person.Name;
+import seedu.address.model.person.Nationality;
+import seedu.address.model.person.Note;
+import seedu.address.model.person.Nric;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
import seedu.address.model.tag.Tag;
@@ -31,21 +41,98 @@ 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_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_NRIC,
+ PREFIX_GENDER, PREFIX_DOB, PREFIX_DATE, PREFIX_NATIONALITY, PREFIX_ADDRESS, PREFIX_TAG);
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
- || !argMultimap.getPreamble().isEmpty()) {
+ StringBuilder missingFieldsHeader = new StringBuilder("Missing required field: ");
+ StringBuilder missingFieldsExamples = new StringBuilder("Eg: ");
+ boolean hasMissingFields = false;
+
+ if (!argMultimap.getValue(PREFIX_NAME).isPresent()) {
+ missingFieldsHeader.append("name (n/) ");
+ missingFieldsExamples.append("n/John Doe ");
+ hasMissingFields = true;
+ }
+ if (!argMultimap.getValue(PREFIX_PHONE).isPresent()) {
+ missingFieldsHeader.append("phone (p/) ");
+ missingFieldsExamples.append("p/91234567 ");
+ hasMissingFields = true;
+ }
+ if (!argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
+ missingFieldsHeader.append("email (e/) ");
+ missingFieldsExamples.append("e/johndoe@example.com ");
+ hasMissingFields = true;
+ }
+ if (!argMultimap.getValue(PREFIX_NRIC).isPresent()) {
+ missingFieldsHeader.append("NRIC (ic/) ");
+ missingFieldsExamples.append("ic/S1234567D ");
+ hasMissingFields = true;
+ }
+ if (!argMultimap.getValue(PREFIX_GENDER).isPresent()) {
+ missingFieldsHeader.append("gender (g/) ");
+ missingFieldsExamples.append("g/Male ");
+ hasMissingFields = true;
+ }
+ if (!argMultimap.getValue(PREFIX_DOB).isPresent()) {
+ missingFieldsHeader.append("date of birth (d/) ");
+ missingFieldsExamples.append("d/20-03-1990 ");
+ hasMissingFields = true;
+ }
+ if (!argMultimap.getValue(PREFIX_DATE).isPresent()) {
+ missingFieldsHeader.append("date of joining (j/) ");
+ missingFieldsExamples.append("j/15-04-2023 ");
+ hasMissingFields = true;
+ }
+ if (!argMultimap.getValue(PREFIX_NATIONALITY).isPresent()) {
+ missingFieldsHeader.append("nationality (nat/) ");
+ missingFieldsExamples.append("nat/Singaporean ");
+ hasMissingFields = true;
+ }
+ if (!argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
+ missingFieldsHeader.append("address (a/) ");
+ missingFieldsExamples.append("a/123 Main Street #05-01/119278 ");
+ hasMissingFields = true;
+ }
+ if (!argMultimap.getValue(PREFIX_TAG).isPresent()) {
+ missingFieldsHeader.append("tag (t/) ");
+ missingFieldsExamples.append("t/Marketing/Full-Time/Product Manager ");
+ hasMissingFields = true;
+ }
+
+ // If any fields are missing, throw ParseException with specific message
+ if (hasMissingFields) {
+ throw new ParseException(
+ missingFieldsHeader.toString().trim() + "\n"
+ + missingFieldsExamples.toString().trim()
+ );
+ }
+
+ // Check for non-empty preamble
+ if (!argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_NRIC,
+ PREFIX_GENDER, PREFIX_DOB, PREFIX_DATE, PREFIX_NATIONALITY, PREFIX_ADDRESS);
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());
+ Nric nric = ParserUtil.parseNric(argMultimap.getValue(PREFIX_NRIC).get());
+ Gender gender = ParserUtil.parseGender(argMultimap.getValue(PREFIX_GENDER).get());
+ Dob dob = ParserUtil.parseDob(argMultimap.getValue(PREFIX_DOB).get());
+ DateOfJoining dateOfJoining = ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get());
+
+ if (!dateOfJoining.toLocalDate().isAfter(dob.toLocalDate())) {
+ throw new ParseException("Date of Joining must be after DOB.");
+ }
+
+ Nationality nationality = ParserUtil.parseNationality(argMultimap.getValue(PREFIX_NATIONALITY).get());
Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
- Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
+ Note note = new Note("");
+ Tag tag = ParserUtil.parseTag(argMultimap.getValue(PREFIX_TAG).get());
- Person person = new Person(name, phone, email, address, tagList);
+ Person person = new Person(name, phone, email, nric, gender, dob, dateOfJoining,
+ nationality, address, note, tag);
return new AddCommand(person);
}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
index 3149ee07e0b..ed656996a9a 100644
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
@@ -14,9 +14,14 @@
import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.ExitCommand;
+import seedu.address.logic.commands.FindByDepartmentCommand;
+import seedu.address.logic.commands.FindByEmploymentTypeCommand;
+import seedu.address.logic.commands.FindByJobTitleCommand;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.NoteCommand;
+import seedu.address.logic.commands.ViewCommand;
import seedu.address.logic.parser.exceptions.ParseException;
/**
@@ -52,7 +57,6 @@ public Command parseCommand(String userInput) throws ParseException {
logger.fine("Command word: " + commandWord + "; Arguments: " + arguments);
switch (commandWord) {
-
case AddCommand.COMMAND_WORD:
return new AddCommandParser().parse(arguments);
@@ -65,8 +69,23 @@ public Command parseCommand(String userInput) throws ParseException {
case ClearCommand.COMMAND_WORD:
return new ClearCommand();
+ case ViewCommand.COMMAND_WORD:
+ return new ViewCommandParser().parse(arguments);
+
case FindCommand.COMMAND_WORD:
- return new FindCommandParser().parse(arguments);
+ if (!arguments.trim().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+ return new FindCommand();
+
+ case FindByDepartmentCommand.COMMAND_WORD:
+ return new FindByDepartmentCommandParser().parse(arguments);
+
+ case FindByEmploymentTypeCommand.COMMAND_WORD:
+ return new FindByEmploymentTypeCommandParser().parse(arguments);
+
+ case FindByJobTitleCommand.COMMAND_WORD:
+ return new FindByJobTitleCommandParser().parse(arguments);
case ListCommand.COMMAND_WORD:
return new ListCommand();
@@ -77,10 +96,14 @@ public Command parseCommand(String userInput) throws ParseException {
case HelpCommand.COMMAND_WORD:
return new HelpCommand();
+ case NoteCommand.COMMAND_WORD:
+ return new NoteCommandParser().parse(arguments);
+
default:
logger.finer("This user input caused a ParseException: " + userInput);
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
+
}
}
diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java
index 75b1a9bf119..de4a6a9915c 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java
@@ -9,7 +9,11 @@ public class CliSyntax {
public static final Prefix PREFIX_NAME = new Prefix("n/");
public static final Prefix PREFIX_PHONE = new Prefix("p/");
public static final Prefix PREFIX_EMAIL = new Prefix("e/");
+ public static final Prefix PREFIX_NRIC = new Prefix("ic/");
+ public static final Prefix PREFIX_GENDER = new Prefix("g/");
+ public static final Prefix PREFIX_DOB = new Prefix("d/");
+ public static final Prefix PREFIX_DATE = new Prefix("j/");
+ public static final Prefix PREFIX_NATIONALITY = new Prefix("nat/");
public static final Prefix PREFIX_ADDRESS = new Prefix("a/");
public static final Prefix PREFIX_TAG = new Prefix("t/");
-
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
index 3527fe76a3e..480a780c420 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
@@ -1,7 +1,5 @@
package seedu.address.logic.parser;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.parser.exceptions.ParseException;
@@ -18,11 +16,10 @@ public class DeleteCommandParser implements Parser {
*/
public DeleteCommand parse(String args) throws ParseException {
try {
- Index index = ParserUtil.parseIndex(args);
+ Index index = ParserUtil.parseIndex(args, DeleteCommand.MESSAGE_USAGE);
return new DeleteCommand(index);
} catch (ParseException pe) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
+ throw pe;
}
}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
index 46b3309a78b..2babc919523 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
@@ -1,23 +1,22 @@
package seedu.address.logic.parser;
import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DOB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GENDER;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NATIONALITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NRIC;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Optional;
-import java.util.Set;
-
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.person.Dob;
/**
* Parses input arguments and creates a new EditCommand object
@@ -32,17 +31,19 @@ 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_NAME, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_GENDER, PREFIX_DOB, PREFIX_DATE, PREFIX_NATIONALITY, PREFIX_ADDRESS, PREFIX_TAG);
Index index;
try {
- index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ index = ParserUtil.parseIndex(argMultimap.getPreamble(), EditCommand.MESSAGE_USAGE);
} catch (ParseException pe) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
+ throw new ParseException(pe.getMessage());
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_NRIC,
+ PREFIX_GENDER, PREFIX_DOB, PREFIX_DATE, PREFIX_NATIONALITY, PREFIX_ADDRESS, PREFIX_TAG);
EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
@@ -55,31 +56,28 @@ public EditCommand parse(String args) throws ParseException {
if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
}
+ if (argMultimap.getValue(PREFIX_GENDER).isPresent()) {
+ editPersonDescriptor.setGender(ParserUtil.parseGender(argMultimap.getValue(PREFIX_GENDER).get()));
+ }
+ if (argMultimap.getValue(PREFIX_DOB).isPresent()) {
+ Dob dob = ParserUtil.parseDob(argMultimap.getValue(PREFIX_DOB).get());
+ editPersonDescriptor.setDob(ParserUtil.parseDob(argMultimap.getValue(PREFIX_DOB).get()));
+ }
+ if (argMultimap.getValue(PREFIX_DATE).isPresent()) {
+ editPersonDescriptor.setDateOfJoining(ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_NATIONALITY).isPresent()) {
+ editPersonDescriptor.setNationality(ParserUtil
+ .parseNationality(argMultimap.getValue(PREFIX_NATIONALITY).get()));
+ }
if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
}
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
-
- if (!editPersonDescriptor.isAnyFieldEdited()) {
- throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
+ if (argMultimap.getValue(PREFIX_TAG).isPresent()) {
+ editPersonDescriptor.setTag(ParserUtil.parseTag(argMultimap.getValue(PREFIX_TAG).get()));
}
return new EditCommand(index, editPersonDescriptor);
}
- /**
- * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty.
- * If {@code tags} contain only one element which is an empty string, it will be parsed into a
- * {@code Set} containing zero tags.
- */
- private Optional> parseTagsForEdit(Collection tags) throws ParseException {
- assert tags != null;
-
- if (tags.isEmpty()) {
- return Optional.empty();
- }
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
- }
-
}
diff --git a/src/main/java/seedu/address/logic/parser/FindByDepartmentCommandParser.java b/src/main/java/seedu/address/logic/parser/FindByDepartmentCommandParser.java
new file mode 100644
index 00000000000..07cc7c4ca3e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindByDepartmentCommandParser.java
@@ -0,0 +1,35 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.logic.commands.FindByDepartmentCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.DepartmentContainsKeywordPredicate;
+import seedu.address.model.tag.Department;
+
+/**
+ * Parses input arguments and creates a new FindByDepartmentCommand object
+ */
+public class FindByDepartmentCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindByDepartmentCommand
+ * and returns a FindByDepartmentCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindByDepartmentCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindByDepartmentCommand.MESSAGE_USAGE));
+ }
+
+ // Check if the department is valid (exists in the list of valid departments)
+ if (!Department.isValidDepartment(trimmedArgs)) {
+ throw new ParseException("Department does not exist. " + Department.MESSAGE_CONSTRAINTS);
+ }
+
+ // Now we only have the department keyword, so we can directly pass it to the predicate
+ return new FindByDepartmentCommand(new DepartmentContainsKeywordPredicate(trimmedArgs));
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/parser/FindByEmploymentTypeCommandParser.java b/src/main/java/seedu/address/logic/parser/FindByEmploymentTypeCommandParser.java
new file mode 100644
index 00000000000..470c226400c
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindByEmploymentTypeCommandParser.java
@@ -0,0 +1,46 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.logic.commands.FindByEmploymentTypeCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.EmploymentTypeContainsKeywordPredicate;
+
+/**
+ * Parses input arguments and creates a new FindByEmploymentTypeCommand object
+ */
+public class FindByEmploymentTypeCommandParser implements Parser {
+
+ public static final String MESSAGE_EMPLOYMENTTYPE_CONSTRAINTS =
+ "Employment type search terms should only contain alphabetic characters, hyphens, and spaces";
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindByEmploymentTypeCommand
+ * and returns a FindByEmploymentTypeCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindByEmploymentTypeCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindByEmploymentTypeCommand.MESSAGE_USAGE));
+ }
+
+ // Validate that employment type only contains alphabetic characters, hyphens, and spaces
+ if (!isValidEmploymentTypeCharacters(trimmedArgs)) {
+ throw new ParseException(MESSAGE_EMPLOYMENTTYPE_CONSTRAINTS);
+ }
+
+ // Now we only have the employment type keyword, so we can directly pass it to the predicate
+ return new FindByEmploymentTypeCommand(new EmploymentTypeContainsKeywordPredicate(trimmedArgs));
+ }
+
+ /**
+ * Returns true if the employment type contains only alphabetic characters, hyphens, and spaces.
+ */
+ private boolean isValidEmploymentTypeCharacters(String employmentType) {
+ return employmentType.chars()
+ .allMatch(c -> Character.isLetter(c) || c == '-' || Character.isWhitespace(c));
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/parser/FindByJobTitleCommandParser.java b/src/main/java/seedu/address/logic/parser/FindByJobTitleCommandParser.java
new file mode 100644
index 00000000000..db50abda00c
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindByJobTitleCommandParser.java
@@ -0,0 +1,40 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.logic.commands.FindByJobTitleCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.JobTitleContainsKeywordPredicate;
+
+/**
+ * Parses input arguments and creates a new FindByJobTitleCommand object
+ */
+public class FindByJobTitleCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindByJobTitleCommand
+ * and returns a FindByJobTitleCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindByJobTitleCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindByJobTitleCommand.MESSAGE_USAGE));
+ }
+
+ // Validate that job title only contains alphabetic characters and spaces
+ if (!isValidJobTitleCharacters(trimmedArgs)) {
+ throw new ParseException(FindByJobTitleCommand.MESSAGE_JOBTITLE_CONSTRAINTS);
+ }
+
+ return new FindByJobTitleCommand(new JobTitleContainsKeywordPredicate(trimmedArgs));
+ }
+
+ /**
+ * Returns true if the job title contains only alphabetic characters and spaces.
+ */
+ private boolean isValidJobTitleCharacters(String jobTitle) {
+ return jobTitle.chars()
+ .allMatch(c -> Character.isLetter(c) || Character.isWhitespace(c));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
index 2867bde857b..dcebc414e10 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
@@ -1,33 +1,28 @@
package seedu.address.logic.parser;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-
-import java.util.Arrays;
-
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
/**
- * Parses input arguments and creates a new FindCommand object
+ * Parses input arguments and creates a new FindCommand object that returns an error.
*/
public class FindCommandParser implements Parser {
/**
* Parses the given {@code String} of arguments in the context of the FindCommand
- * and returns a FindCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
+ * and returns a Command object for execution.
+ * @throws ParseException if the user input does not conform to the expected format
*/
+ @Override
public FindCommand parse(String args) throws ParseException {
String trimmedArgs = args.trim();
- if (trimmedArgs.isEmpty()) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
- }
- String[] nameKeywords = trimmedArgs.split("\\s+");
+ // No arguments should be processed for the "find" command, it just throws an error
+ if (!trimmedArgs.isEmpty()) {
+ throw new ParseException("Invalid command format! Please use 'findByDepartment',"
+ + "'findByEmploymentType', or 'findByJobTitle' instead.");
+ }
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ return new FindCommand(); // Simply return the FindCommand to show the error message
}
-
}
diff --git a/src/main/java/seedu/address/logic/parser/NoteCommandParser.java b/src/main/java/seedu/address/logic/parser/NoteCommandParser.java
new file mode 100644
index 00000000000..415bebacf18
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/NoteCommandParser.java
@@ -0,0 +1,41 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.NoteCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Note;
+
+/**
+ * Parses input arguments and creates a new {@code RemarkCommand} object
+ */
+public class NoteCommandParser implements Parser {
+
+ public static final String MESSAGE_ADD_NOTE_SUCCESS = "Added note to Person: %1$s";
+ public static final String MESSAGE_DELETE_NOTE_SUCCESS = "Removed note from Person: %1$s";
+ /**
+ * Parses the given {@code String} of arguments in the context of the {@code NoteCommand}
+ * and returns a {@code NoteCommand} object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public NoteCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ String trimmedArgs = args.trim();
+ String[] input = trimmedArgs.split(" ", 2);
+ if (input[0].isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, NoteCommand.MESSAGE_USAGE));
+ }
+
+ Index index;
+ try {
+ index = ParserUtil.parseIndex(input[0], NoteCommand.MESSAGE_USAGE);
+ } catch (ParseException pe) {
+ throw pe;
+ }
+
+ return input.length == 1 ? new NoteCommand(index, new Note(" ")) : new NoteCommand(index, new Note(input[1]));
+
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..146919d9c30 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -1,18 +1,29 @@
package seedu.address.logic.parser;
import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.StringUtil;
+import seedu.address.logic.Messages;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.Address;
+import seedu.address.model.person.DateOfJoining;
+import seedu.address.model.person.Dob;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Gender;
import seedu.address.model.person.Name;
+import seedu.address.model.person.Nationality;
+import seedu.address.model.person.Nric;
import seedu.address.model.person.Phone;
+import seedu.address.model.tag.Department;
+import seedu.address.model.tag.EmploymentType;
+import seedu.address.model.tag.JobTitle;
import seedu.address.model.tag.Tag;
/**
@@ -27,11 +38,28 @@ public class ParserUtil {
* trimmed.
* @throws ParseException if the specified index is invalid (not non-zero unsigned integer).
*/
- public static Index parseIndex(String oneBasedIndex) throws ParseException {
+ public static Index parseIndex(String oneBasedIndex, String commandUsage) throws ParseException {
String trimmedIndex = oneBasedIndex.trim();
+
+ try {
+ long parsedIndex = Long.parseLong(trimmedIndex);
+
+ if (parsedIndex > Integer.MAX_VALUE || parsedIndex < Integer.MIN_VALUE) {
+ throw new ParseException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ } catch (NumberFormatException e) {
+ if (!trimmedIndex.matches("\\d+")) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, commandUsage), e);
+ } else {
+ throw new ParseException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX, e);
+ }
+ }
+
if (!StringUtil.isNonZeroUnsignedInteger(trimmedIndex)) {
- throw new ParseException(MESSAGE_INVALID_INDEX);
+ throw new ParseException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
}
+
return Index.fromOneBased(Integer.parseInt(trimmedIndex));
}
@@ -96,29 +124,210 @@ public static Email parseEmail(String email) throws ParseException {
}
/**
- * Parses a {@code String tag} into a {@code Tag}.
+ * Parses a {@code String nric} into an {@code Nric}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code tag} is invalid.
+ * @throws ParseException if the given {@code nric} 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 Nric parseNric(String nric) throws ParseException {
+ requireNonNull(nric);
+ String trimmedNric = nric.trim();
+ if (!Nric.isValidNric(trimmedNric)) {
+ throw new ParseException(Nric.MESSAGE_CONSTRAINTS);
}
- return new Tag(trimmedTag);
+ return new Nric(trimmedNric);
}
/**
- * Parses {@code Collection tags} into a {@code Set}.
+ * Parses a {@code String gender} into an {@code Gender}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code gender} 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 Gender parseGender(String gender) throws ParseException {
+ requireNonNull(gender);
+ String trimmedGender = gender.trim();
+ if (!Gender.isValidGender(trimmedGender)) {
+ throw new ParseException(Gender.MESSAGE_CONSTRAINTS);
+ }
+ return new Gender(trimmedGender);
+ }
+
+ /**
+ * Parses a {@code String dob} into an {@code Dob}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code dob} is invalid.
+ */
+ public static Dob parseDob(String dob) throws ParseException {
+ requireNonNull(dob);
+ String trimmedDob = dob.trim();
+
+ if (!Dob.isValidDob(trimmedDob)) {
+ throw new ParseException(Dob.MESSAGE_CONSTRAINTS);
+ }
+ if (!Dob.isValidDate(trimmedDob)) {
+ throw new ParseException(Dob.DATE_INVALID_MESSAGE);
+ }
+
+ List formats = List.of(
+ "dd-MMM-yyyy",
+ "dd/MM/yyyy",
+ "dd.MM.yyyy",
+ "yyyy-MM-dd",
+ "dd-MM-yyyy"
+ );
+
+
+ Date parsedDate = null;
+ java.text.ParseException lastException = null;
+
+ for (String format : formats) {
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.ENGLISH);
+ sdf.setLenient(false); // Strict parsing
+ parsedDate = sdf.parse(trimmedDob);
+ break; // Stop once a valid format is found
+ } catch (java.text.ParseException e) {
+ lastException = e;
+ }
+ }
+
+ if (parsedDate == null) {
+ throw new ParseException(Dob.DATE_INVALID_MESSAGE);
+ }
+
+ // Check if date is in the future
+ Date today = new Date();
+ if (parsedDate.after(today)) {
+ throw new ParseException(Dob.FUTURE_DATE_INVALID);
+ }
+
+ // Always return the date in "dd-MMM-yyyy" format
+ SimpleDateFormat outputFormat = new SimpleDateFormat("dd-MMM-yyyy", Locale.ENGLISH);
+ return new Dob(outputFormat.format(parsedDate));
+ }
+
+ /**
+ * Parses a {@code String dateOfJoining} into an {@code DateOfJoining}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code dateOfJoining} is invalid.
+ */
+ public static DateOfJoining parseDate(String dateOfJoining) throws ParseException {
+ requireNonNull(dateOfJoining);
+ String trimmedDate = dateOfJoining.trim();
+
+ if (!DateOfJoining.isValidDate(trimmedDate)) {
+ throw new ParseException(DateOfJoining.MESSAGE_CONSTRAINTS);
+ }
+
+ if (!DateOfJoining.isAValidDate(trimmedDate)) {
+ throw new ParseException(DateOfJoining.DATE_INVALID_MESSAGE);
+ }
+
+ List formats = List.of(
+ "dd-MMM-yyyy",
+ "dd/MM/yyyy",
+ "dd.MM.yyyy",
+ "yyyy-MM-dd",
+ "dd-MM-yyyy"
+ );
+
+ Date parsedDate = null;
+ java.text.ParseException lastException = null;
+
+ for (String format : formats) {
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.ENGLISH);
+ sdf.setLenient(false); // Strict parsing
+ parsedDate = sdf.parse(trimmedDate);
+ break; // Stop once a valid format is found
+ } catch (java.text.ParseException e) {
+ lastException = e;
+ }
+ }
+
+ if (parsedDate == null) {
+ throw new ParseException(DateOfJoining.DATE_INVALID_MESSAGE);
+ }
+
+ // Always return the date in "dd-MMM-yyyy" format
+ SimpleDateFormat outputFormat = new SimpleDateFormat("dd-MMM-yyyy", Locale.ENGLISH);
+ return new DateOfJoining(outputFormat.format(parsedDate));
+ }
+
+ /**
+ * Parses a {@code String nationality} into an {@code Nationality}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code nationality} is invalid.
+ */
+ public static Nationality parseNationality(String nationality) throws ParseException {
+ requireNonNull(nationality);
+ String trimmedNationality = nationality.trim();
+ if (!Nationality.isValidNationality(trimmedNationality)) {
+ throw new ParseException(Nationality.MESSAGE_CONSTRAINTS);
+ }
+ return new Nationality(trimmedNationality);
+ }
+
+ /**
+ * Parses a {@code String tag} into a {@code Tag}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code tag} is invalid.
+ */
+ public static Tag parseTag(String tags) throws ParseException {
+ try {
+ requireNonNull(tags);
+ String trimmedTags = tags.trim();
+
+ // Check if the input is empty after trimming
+ if (trimmedTags.isEmpty()) {
+ throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
+ }
+
+ String[] tagList = trimmedTags.split("/");
+
+ // Check for incorrect number of components or ends with /
+ if (tagList.length != 3 || trimmedTags.endsWith("/")) {
+ throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
+ }
+
+ // Check if any component is empty
+ for (String tagComponent : tagList) {
+ if (tagComponent.trim().isEmpty()) {
+ throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
+ }
+ }
+
+ // Validate and parse each component
+ if (!Department.isValidDepartmentInput(tagList[0].trim())) {
+ throw new ParseException(Department.MESSAGE_CONSTRAINTS);
+ }
+
+ if (!EmploymentType.isValidEmploymentType(tagList[1].trim())) {
+ throw new ParseException(EmploymentType.MESSAGE_CONSTRAINTS);
+ }
+
+ if (!JobTitle.isValidJobTitle(tagList[2].trim())) {
+ throw new ParseException(JobTitle.MESSAGE_CONSTRAINTS);
+ }
+
+ Department department = new Department(tagList[0].trim());
+ EmploymentType employmentType = new EmploymentType(tagList[1].trim());
+ JobTitle jobTitle = new JobTitle(tagList[2].trim());
+
+ return new Tag(department, employmentType, jobTitle);
+ } catch (NullPointerException e) {
+ throw e;
+ } catch (ParseException pe) {
+ throw pe;
+ } catch (Exception e) {
+ throw new ParseException(e.getMessage());
}
- return tagSet;
}
}
+
+
diff --git a/src/main/java/seedu/address/logic/parser/ViewCommandParser.java b/src/main/java/seedu/address/logic/parser/ViewCommandParser.java
new file mode 100644
index 00000000000..c94a9701781
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ViewCommandParser.java
@@ -0,0 +1,38 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.List;
+
+import seedu.address.logic.commands.ViewCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.ProfileContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new ViewCommand object
+ */
+public class ViewCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the ViewCommand
+ * and returns a ViewCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ViewCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewCommand.MESSAGE_USAGE));
+ }
+
+ // Check if input contains only letters and spaces (allow multiple words)
+ if (!trimmedArgs.matches("^[a-zA-Z\\s]+$")) {
+ throw new ParseException("Names should only contain alphabetical characters and spaces.");
+ }
+
+ // Pass the full name as a single keyword
+ List profileKeywords = List.of(trimmedArgs.toLowerCase());
+
+ return new ViewCommand(new ProfileContainsKeywordsPredicate(profileKeywords));
+ }
+}
+
diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/address/model/UserPrefs.java
index 6be655fb4c7..69c1ebc107e 100644
--- a/src/main/java/seedu/address/model/UserPrefs.java
+++ b/src/main/java/seedu/address/model/UserPrefs.java
@@ -14,7 +14,7 @@
public class UserPrefs implements ReadOnlyUserPrefs {
private GuiSettings guiSettings = new GuiSettings();
- private Path addressBookFilePath = Paths.get("data" , "addressbook.json");
+ private Path addressBookFilePath = Paths.get("data" , "hrelper.json");
/**
* Creates a {@code UserPrefs} with default values.
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java
index 469a2cc9a1e..5569e2e4fc4 100644
--- a/src/main/java/seedu/address/model/person/Address.java
+++ b/src/main/java/seedu/address/model/person/Address.java
@@ -8,14 +8,25 @@
* Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)}
*/
public class Address {
+ public static final String MESSAGE_CONSTRAINTS = "Addresses should follow the format: [ADDRESS]/[POSTAL CODE]\n"
+ + "where [address] is the street address and [postal code] is a valid 6-digit Singapore postal code.\n"
+ + "The first two digits of the postal code "
+ + "must be a valid Singapore postal district (01–82, excluding 74).\n"
+ + "Example: Blk 123 Clementi Avenue 3/123456";
- public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank";
+ // Regex to validate the full address format: any text, followed by slash (with optional spaces), then 6 digits
+ private static final String ADDRESS_VALIDATION_REGEX = ".+\\s*/\\s*\\d{6}$";
- /*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
- */
- public static final String VALIDATION_REGEX = "[^\\s].*";
+ // Valid first two digits of Singapore postal codes
+ private static final String[] VALID_POSTAL_PREFIXES = { "01", "02", "03", "04", "05", "06", "07", "08", "09", "10",
+ "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
+ "21", "22", "23", "24", "25", "26", "27", "28", "29", "30",
+ "31", "32", "33", "34", "35", "36", "37", "38", "39", "40",
+ "41", "42", "43", "44", "45", "46", "47", "48", "49", "50",
+ "51", "52", "53", "54", "55", "56", "57", "58", "59", "60",
+ "61", "62", "63", "64", "65", "66", "67", "68", "69", "70",
+ "71", "72", "73", "75", "76", "77", "78", "79", "80", "81", "82"
+ };
public final String value;
@@ -27,14 +38,51 @@ public class Address {
public Address(String address) {
requireNonNull(address);
checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS);
- value = address;
+ // Normalize the address by removing excess whitespace around the slash
+ value = normalizeAddress(address);
}
/**
- * Returns true if a given string is a valid email.
+ * Normalizes the address by removing excess whitespace around the slash separator.
+ */
+ private String normalizeAddress(String address) {
+ // Split by slash, trim whitespace from each part, then rejoin
+ String[] parts = address.split("/");
+ if (parts.length == 2) {
+ return parts[0].trim() + "/" + parts[1].trim();
+ }
+ return address.trim();
+ }
+
+ /**
+ * Returns true if a given string is a valid address with valid Singapore postal code.
*/
public static boolean isValidAddress(String test) {
- return test.matches(VALIDATION_REGEX);
+ // Check if the address matches the basic format (allowing whitespace around the slash)
+ if (!test.matches(ADDRESS_VALIDATION_REGEX)) {
+ return false;
+ }
+
+ // Extract the postal code (last 6 digits)
+ String[] parts = test.split("/");
+ String postalCodePart = parts[1].trim();
+ String postalCode = postalCodePart.replaceAll("\\s+", "");
+
+ // Check if postal code is 6 digits
+ if (!postalCode.matches("\\d{6}")) {
+ return false;
+ }
+
+ String postalPrefix = postalCode.substring(0, 2);
+
+ // Check if the first two digits are a valid postal district
+ for (String prefix : VALID_POSTAL_PREFIXES) {
+ if (prefix.equals(postalPrefix)) {
+ return true;
+ }
+ }
+
+ return false;
}
@Override
@@ -48,7 +96,6 @@ public boolean equals(Object other) {
return true;
}
- // instanceof handles nulls
if (!(other instanceof Address)) {
return false;
}
@@ -61,5 +108,5 @@ public boolean equals(Object other) {
public int hashCode() {
return value.hashCode();
}
-
}
+
diff --git a/src/main/java/seedu/address/model/person/DateOfJoining.java b/src/main/java/seedu/address/model/person/DateOfJoining.java
new file mode 100644
index 00000000000..263221167f0
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/DateOfJoining.java
@@ -0,0 +1,112 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.Locale;
+
+/**
+ * Represents a Person's dateOfJoining in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidDate(String)}
+ */
+public class DateOfJoining {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Format of DateOfJoining should be one of the following: dd-MMM-yyyy, dd/MM/yyyy, dd.MM.yyyy, yyyy-MM-dd, "
+ + "dd-MM-yyyy. DateOfJoining should not be blank.";
+
+ public static final String VALIDATION_REGEX =
+ "^(\\d{2}-[A-Za-z]{3}-\\d{4}"
+ + "|\\d{2}/\\d{2}/\\d{4}"
+ + "|\\d{2}\\.\\d{2}\\.\\d{4}"
+ + "|\\d{4}-\\d{2}-\\d{2}"
+ + "|\\d{2}-\\d{2}-\\d{4})$";
+
+
+ public static final String DATE_INVALID_MESSAGE = "The date given for DateOfJoining is invalid.";
+
+ private static final DateTimeFormatter[] DATE_FORMATTERS = new DateTimeFormatter[] {
+ DateTimeFormatter.ofPattern("dd-MMM-yyyy").withLocale(Locale.ENGLISH),
+ DateTimeFormatter.ofPattern("dd/MM/yyyy"),
+ DateTimeFormatter.ofPattern("dd.MM.yyyy"),
+ DateTimeFormatter.ofPattern("dd-MM-yyyy"),
+ DateTimeFormatter.ofPattern("yyyy-MM-dd")
+ };
+
+ public final String value;
+
+ /**
+ * Constructs an {@code DateOfJoining}
+ *
+ * @param dateOfJoining A valid DateOfJoining.
+ */
+ public DateOfJoining(String dateOfJoining) {
+ requireNonNull(dateOfJoining);
+ checkArgument(isValidDate(dateOfJoining), MESSAGE_CONSTRAINTS);
+ checkArgument(isAValidDate(dateOfJoining), DATE_INVALID_MESSAGE);
+ value = dateOfJoining;
+ }
+
+ /**
+ * Returns if a given string is a valid date.
+ */
+ public static boolean isValidDate(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ /**
+ * Returns if a given string is a valid date.
+ */
+ public static boolean isAValidDate(String test) {
+ for (DateTimeFormatter formatter : DATE_FORMATTERS) {
+ try {
+ LocalDate.parse(test, formatter);
+ return true;
+ } catch (DateTimeParseException e) {
+ //
+ }
+ }
+ return false;
+ }
+
+ /**
+ * For converting to local date to compare with DOB
+ */
+ public LocalDate toLocalDate() {
+ for (DateTimeFormatter formatter : DATE_FORMATTERS) {
+ try {
+ return LocalDate.parse(value, formatter);
+ } catch (DateTimeParseException e) {
+ // try next formatter
+ }
+ }
+ throw new IllegalStateException("Invalid date format stored in value.");
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof DateOfJoining)) {
+ return false;
+ }
+
+ DateOfJoining otherDate = (DateOfJoining) other;
+ return value.equals(otherDate.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/DepartmentContainsKeywordPredicate.java b/src/main/java/seedu/address/model/person/DepartmentContainsKeywordPredicate.java
new file mode 100644
index 00000000000..ed89122da48
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/DepartmentContainsKeywordPredicate.java
@@ -0,0 +1,63 @@
+package seedu.address.model.person;
+
+import java.util.function.Predicate;
+
+import seedu.address.model.tag.Department;
+
+/**
+ * Tests whether a {@code Person}'s department matches a given keyword.
+ */
+public class DepartmentContainsKeywordPredicate implements Predicate {
+ private final String keyword;
+
+ /**
+ * Constructs a predicate to test if a person's department contains the given keyword.
+ *
+ * @param keyword The keyword to match against the person's department.
+ */
+ public DepartmentContainsKeywordPredicate(String keyword) {
+ this.keyword = keyword.toLowerCase();
+ }
+
+ @Override
+ public boolean test(Person person) {
+ String department = person.getTag().getValue()[0]; // Get department from tag
+
+ // Check for exact match with department name (case insensitive)
+ if (department.equalsIgnoreCase(keyword)) {
+ return true;
+ }
+
+ // Check if the keyword is a valid short form
+ try {
+ // If the keyword is a valid short form, it will be mapped to a full department
+ String mappedDepartment = Department.mapInput(keyword);
+
+ // Check if the mapped department matches the person's department
+ return department.equalsIgnoreCase(mappedDepartment);
+ } catch (IllegalArgumentException e) {
+ // If mapping fails, it means the keyword is not a valid short form
+ // Check for partial match with department name (case insensitive)
+ if (keyword.length() >= 3) { // Only consider partial matches for keywords of 3+ characters
+ return department.toLowerCase().contains(keyword);
+ }
+
+ return false;
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof DepartmentContainsKeywordPredicate)) {
+ return false;
+ }
+
+ DepartmentContainsKeywordPredicate otherPredicate = (DepartmentContainsKeywordPredicate) other;
+ return keyword.equals(otherPredicate.keyword);
+ }
+}
+
diff --git a/src/main/java/seedu/address/model/person/Dob.java b/src/main/java/seedu/address/model/person/Dob.java
new file mode 100644
index 00000000000..3a091fe73b4
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Dob.java
@@ -0,0 +1,116 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.Locale;
+
+/**
+ * Represents a Person's dob in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidDob(String)}
+ */
+public class Dob {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Format of DOB should be one of the following: dd-MMM-yyyy, dd/MM/yyyy, dd.MM.yyyy, yyyy-MM-dd, "
+ + "dd-MM-yyyy. DOB should not be blank.";
+
+ public static final String VALIDATION_REGEX =
+ "^(\\d{2}-[A-Za-z]{3}-\\d{4}"
+ + "|\\d{2}/\\d{2}/\\d{4}"
+ + "|\\d{2}\\.\\d{2}\\.\\d{4}"
+ + "|\\d{4}-\\d{2}-\\d{2}"
+ + "|\\d{2}-\\d{2}-\\d{4})$";
+
+
+ public static final String DATE_INVALID_MESSAGE = "The date given for DOB is invalid.";
+ public static final String FUTURE_DATE_INVALID = "DOB cannot be in the future.";
+
+ private static final DateTimeFormatter[] DATE_FORMATTERS = new DateTimeFormatter[] {
+ DateTimeFormatter.ofPattern("dd-MMM-yyyy").withLocale(Locale.ENGLISH),
+ DateTimeFormatter.ofPattern("dd/MM/yyyy"),
+ DateTimeFormatter.ofPattern("dd.MM.yyyy"),
+ DateTimeFormatter.ofPattern("dd-MM-yyyy"),
+ DateTimeFormatter.ofPattern("yyyy-MM-dd")
+ };
+
+ public final String value;
+
+ /**
+ * Constructs an {@code Dob}
+ *
+ * @param dob A valid Dob.
+ */
+ public Dob(String dob) {
+ requireNonNull(dob);
+ checkArgument(isValidDob(dob), MESSAGE_CONSTRAINTS);
+ checkArgument(isValidDate(dob), DATE_INVALID_MESSAGE);
+ value = dob;
+ }
+
+ /**
+ * Returns if a given string is a valid dob.
+ */
+ public static boolean isValidDob(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ /**
+ * Returns if a given string is a valid date.
+ */
+ public static boolean isValidDate(String test) {
+ for (DateTimeFormatter formatter : DATE_FORMATTERS) {
+ try {
+ LocalDate date = LocalDate.parse(test, formatter);
+ if (date != null) {
+ return true; // Valid date
+ }
+ return true;
+ } catch (DateTimeParseException e) {
+ // Try next formatter
+ }
+ }
+ return false;
+ }
+
+ /**
+ * For converting to local date to compare with DateOfJoining
+ */
+ public LocalDate toLocalDate() {
+ for (DateTimeFormatter formatter : DATE_FORMATTERS) {
+ try {
+ return LocalDate.parse(value, formatter);
+ } catch (DateTimeParseException e) {
+ // try next formatter
+ }
+ }
+ throw new IllegalStateException("Invalid date format stored in value.");
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Dob)) {
+ return false;
+ }
+
+ Dob otherDob = (Dob) other;
+ return otherDob.value.equals(value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/address/model/person/Email.java
index c62e512bc29..75ec5939c21 100644
--- a/src/main/java/seedu/address/model/person/Email.java
+++ b/src/main/java/seedu/address/model/person/Email.java
@@ -19,6 +19,7 @@ public class Email {
+ "separated by periods.\n"
+ "The domain name must:\n"
+ " - end with a domain label at least 2 characters long\n"
+ + " - have at least a '.' character between domain labels\n"
+ " - have each domain label start and end with alphanumeric characters\n"
+ " - have each domain label consist of alphanumeric characters, separated only by hyphens, if any.";
// alphanumeric and special characters
@@ -28,7 +29,7 @@ public class Email {
private static final String DOMAIN_PART_REGEX = ALPHANUMERIC_NO_UNDERSCORE
+ "(-" + ALPHANUMERIC_NO_UNDERSCORE + ")*";
private static final String DOMAIN_LAST_PART_REGEX = "(" + DOMAIN_PART_REGEX + "){2,}$"; // At least two chars
- private static final String DOMAIN_REGEX = "(" + DOMAIN_PART_REGEX + "\\.)*" + DOMAIN_LAST_PART_REGEX;
+ private static final String DOMAIN_REGEX = "(" + DOMAIN_PART_REGEX + "\\.)+" + DOMAIN_LAST_PART_REGEX;
public static final String VALIDATION_REGEX = LOCAL_PART_REGEX + "@" + DOMAIN_REGEX;
public final String value;
diff --git a/src/main/java/seedu/address/model/person/EmploymentTypeContainsKeywordPredicate.java b/src/main/java/seedu/address/model/person/EmploymentTypeContainsKeywordPredicate.java
new file mode 100644
index 00000000000..63a86a19425
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/EmploymentTypeContainsKeywordPredicate.java
@@ -0,0 +1,83 @@
+package seedu.address.model.person;
+
+import java.util.function.Predicate;
+
+/**
+ * Tests whether a {@code Person}'s employment type matches a given keyword.
+ */
+public class EmploymentTypeContainsKeywordPredicate implements Predicate {
+ private static final int MIN_KEYWORD_LENGTH = 3;
+ private final String keyword;
+
+ /**
+ * Constructs a predicate to test if a person's employment type matches the given keyword.
+ *
+ * @param keyword The keyword to match against the person's employment type.
+ */
+ public EmploymentTypeContainsKeywordPredicate(String keyword) {
+ this.keyword = keyword.toLowerCase();
+ }
+
+ @Override
+ public boolean test(Person person) {
+ String employmentType = person.getTag().getValue()[1]; // Get employment type from tag
+
+ // For multi-word searches, treat as a single phrase
+ if (keyword.contains(" ")) {
+ // Check if the entire phrase appears in the employment type
+ return employmentType.toLowerCase().equals(keyword);
+ }
+
+ // For single-word searches
+ // Exact match for the employment type (case insensitive)
+ if (employmentType.toLowerCase().equals(keyword)) {
+ return true;
+ }
+
+ // Check the specific common types (Full-time, Part-time, Contract, etc.)
+ // Assuming these are the main employment types you want to support
+ switch (keyword) {
+ case "full-time":
+ case "full":
+ case "fulltime":
+ return employmentType.toLowerCase().equals("full-time");
+
+ case "part-time":
+ case "part":
+ case "parttime":
+ return employmentType.toLowerCase().equals("part-time");
+
+ case "contract":
+ case "contractor":
+ return employmentType.toLowerCase().equals("contract");
+
+ case "intern":
+ case "internship":
+ return employmentType.toLowerCase().equals("intern");
+
+ case "temp":
+ case "temporary":
+ return employmentType.toLowerCase().equals("temporary");
+
+ default:
+ // If keyword length >= 3, also check for prefix match
+ return keyword.length() >= MIN_KEYWORD_LENGTH
+ && employmentType.toLowerCase().startsWith(keyword);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof EmploymentTypeContainsKeywordPredicate)) {
+ return false;
+ }
+
+ EmploymentTypeContainsKeywordPredicate otherPredicate = (EmploymentTypeContainsKeywordPredicate) other;
+ return keyword.equals(otherPredicate.keyword);
+ }
+}
+
diff --git a/src/main/java/seedu/address/model/person/Gender.java b/src/main/java/seedu/address/model/person/Gender.java
new file mode 100644
index 00000000000..87bfc81bca2
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Gender.java
@@ -0,0 +1,73 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.util.Set;
+
+/**
+ * Represents a Person's gender in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidGender(String)}
+ */
+public class Gender {
+ public static final String MESSAGE_CONSTRAINTS =
+ "Gender should only be either 'Male', 'Female' or 'Other', and should not be left blank";
+
+ private static final Set VALID_GENDERS = Set.of("Male", "Female", "Other");
+
+ public final String value;
+
+ /**
+ * Constructs a {@code Gender}.
+ *
+ * @param gender A valid Gender.
+ */
+ public Gender(String gender) {
+ requireNonNull(gender);
+ checkArgument(isValidGender(gender), MESSAGE_CONSTRAINTS);
+ value = capitalize(gender);
+ }
+
+ /**
+ * Returns if Gender is valid
+ */
+ public static boolean isValidGender(String gender) {
+ if (gender == null) {
+ throw new NullPointerException(MESSAGE_CONSTRAINTS); // throw NullPointerException instead
+ }
+ return VALID_GENDERS.stream()
+ .anyMatch(validGender -> validGender.equalsIgnoreCase(gender));
+ }
+
+ /**
+ * Capitalizes the gender input (e.g., "male" -> "Male")
+ */
+ private static String capitalize(String gender) {
+ return gender.substring(0, 1).toUpperCase() + gender.substring(1).toLowerCase();
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Gender)) {
+ return false;
+ }
+
+ Gender otherGender = (Gender) other;
+ return value.equals(otherGender.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/person/JobTitleContainsKeywordPredicate.java b/src/main/java/seedu/address/model/person/JobTitleContainsKeywordPredicate.java
new file mode 100644
index 00000000000..44e71847eae
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/JobTitleContainsKeywordPredicate.java
@@ -0,0 +1,62 @@
+package seedu.address.model.person;
+
+import java.util.function.Predicate;
+
+/**
+ * Tests whether a {@code Person}'s job title matches a given keyword.
+ */
+public class JobTitleContainsKeywordPredicate implements Predicate {
+ private final String keyword;
+
+ /**
+ * Constructs a predicate to test if a person's job title matches the given keyword.
+ *
+ * @param keyword The keyword to match against the person's job title.
+ */
+ public JobTitleContainsKeywordPredicate(String keyword) {
+ this.keyword = keyword.toLowerCase();
+ }
+
+ @Override
+ public boolean test(Person person) {
+ String jobTitle = person.getTag().getValue()[2]; // Get job title from tag
+
+ // For multi-word searches, treat as a single phrase
+ if (keyword.contains(" ")) {
+ // Check if the entire phrase appears in the job title
+ return jobTitle.toLowerCase().contains(keyword);
+ }
+
+ // For single-word searches, check if it's a complete word
+ String[] jobTitleWords = jobTitle.toLowerCase().split("\\s+");
+
+ for (String word : jobTitleWords) {
+ // Exact match for the word
+ if (word.equals(keyword)) {
+ return true;
+ }
+
+ // If keyword length >= 3, also check for prefix match
+ if (keyword.length() >= 3 && word.startsWith(keyword)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof JobTitleContainsKeywordPredicate)) {
+ return false;
+ }
+
+ JobTitleContainsKeywordPredicate otherPredicate = (JobTitleContainsKeywordPredicate) other;
+ return keyword.equals(otherPredicate.keyword);
+ }
+}
+
diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/person/Name.java
index 173f15b9b00..c4683075959 100644
--- a/src/main/java/seedu/address/model/person/Name.java
+++ b/src/main/java/seedu/address/model/person/Name.java
@@ -3,6 +3,9 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
/**
* Represents a Person's name in the address book.
* Guarantees: immutable; is valid as declared in {@link #isValidName(String)}
@@ -10,13 +13,15 @@
public class Name {
public static final String MESSAGE_CONSTRAINTS =
- "Names should only contain alphanumeric characters and spaces, and it should not be blank";
+ "Names should only contain letters, hyphens (-), apostrophes ('), slashes (/), periods (.), and spaces. "
+ + "It should not be blank.";
/*
- * The first character of the address must not be a whitespace,
+ * The first character of the name must not be a whitespace,
* otherwise " " (a blank string) becomes a valid input.
*/
- public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+ public static final String VALIDATION_REGEX =
+ "([\\p{L}]+(?:[.\\-'/][\\p{L}]+)*)( ([\\p{L}]+(?:[.\\-'/][\\p{L}]+)*))*";
public final String fullName;
@@ -28,7 +33,23 @@ public class Name {
public Name(String name) {
requireNonNull(name);
checkArgument(isValidName(name), MESSAGE_CONSTRAINTS);
- fullName = name;
+ fullName = capitalizeName(name);
+ }
+
+ /**
+ * Capitalises the first letter of the word, keeping the rest lowercase.
+ * @param name
+ *
+ */
+ public static String capitalizeName(String name) {
+ return Arrays.stream(name.trim().split(" "))
+ .map(part -> {
+ if (part.length() == 0) {
+ return part;
+ }
+ return part.substring(0, 1).toUpperCase() + part.substring(1).toLowerCase();
+ })
+ .collect(Collectors.joining(" "));
}
/**
diff --git a/src/main/java/seedu/address/model/person/Nationality.java b/src/main/java/seedu/address/model/person/Nationality.java
new file mode 100644
index 00000000000..32da3b7ab07
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Nationality.java
@@ -0,0 +1,142 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.util.Set;
+
+/**
+ * Represents a Person's nationality in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidNationality(String)}
+ */
+public class Nationality {
+ private static final String nationalities = " Armenian, Australian, Austrian, Azerbaijani, Bahamian, Bahraini,\n "
+ + "Bangladeshi, Barbadian, Belarusian, Belgian, Belizean, Beninese, Bhutanese,\n "
+ + "Bolivian, Bosnian, Botswanan, Brazilian, British, Bruneian, Bulgarian, Burkinabe,\n "
+ + "Burmese, Burundian, Cambodian, Cameroonian, Canadian, Cape Verdean, Central African,\n "
+ + "Chadian, Chilean, Chinese, Colombian, Comorian, Congolese, Costa Rican, Croatian,\n "
+ + "Cuban, Cypriot, Czech, Danish, Djiboutian, Dominican, Dutch, Ecuadorian, Egyptian,\n "
+ + "Emirati, Equatorial Guinean, Eritrean, Estonian, Ethiopian, Fijian, Filipino,\n "
+ + "Finnish, French, Gabonese, Gambian, Georgian, German, Ghanaian, Greek, Grenadian,\n "
+ + "Guatemalan, Guinean, Guyanese, Haitian, Honduran, Hungarian, Icelandic, Indian,\n "
+ + "Indonesian, Iranian, Iraqi, Irish, Israeli, Italian, Ivorian, Jamaican, Japanese,\n "
+ + "Jordanian, Kazakh, Kenyan, Kiribati, Kuwaiti, Kyrgyz, Laotian, Latvian, Lebanese,\n "
+ + "Liberian, Libyan, Liechtenstein, Lithuanian, Luxembourgish, Malagasy, Malawian,\n "
+ + "Malaysian, Maldivian, Malian, Maltese, Marshallese, Mauritanian, Mauritian, Mexican,\n "
+ + "Micronesian, Moldovan, Monacan, Mongolian, Montenegrin, Moroccan, Mozambican,\n "
+ + "Namibian, Nauruan, Nepalese, New Zealander, Nicaraguan, Nigerien, Nigerian,\n "
+ + "North Korean, North Macedonian, Norwegian, Omani, Pakistani, Palauan, Palestinian,\n "
+ + "Panamanian, Papua New Guinean, Paraguayan, Peruvian, Polish, Portuguese, Qatari,\n "
+ + "Romanian, Russian, Rwandan, Saint Lucian, Salvadoran, Samoan, Saudi Arabian,\n "
+ + "Scottish, Senegalese, Serbian, Seychellois, Sierra Leonean, Singaporean, Slovak,\n "
+ + "Slovenian, Solomon Islander, Somali, South African, South Korean, South Sudanese,\n "
+ + "Spanish, Sri Lankan, Sudanese, Surinamese, Swazi, Swedish, Swiss, Syrian, Tajik,\n "
+ + "Tanzanian, Thai, Timorese, Togolese, Tongan, Trinidadian, Tunisian, Turkish, Turkmen,\n "
+ + "Tuvaluan, Ugandan, Ukrainian, Uruguayan, Uzbek, Vanuatuan, Venezuelan, Vietnamese,\n "
+ + "Welsh, Yemeni, Zambian, Zimbabwean, Other;";
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Nationality must contain only alphabetic characters and may include spaces for multi-word nationalities,"
+ + " but cannot be left blank.\n"
+ + "Here is the list of Nationalities:\n"
+ + nationalities;
+
+ private static final Set VALID_NATIONALITIES = Set.of(
+ "Afghan", "Albanian", "Algerian", "American", "Andorran", "Angolan", "Argentine",
+ "Armenian", "Australian", "Austrian", "Azerbaijani", "Bahamian", "Bahraini",
+ "Bangladeshi", "Barbadian", "Belarusian", "Belgian", "Belizean", "Beninese",
+ "Bhutanese", "Bolivian", "Bosnian", "Botswanan", "Brazilian", "British",
+ "Bruneian", "Bulgarian", "Burkinabe", "Burmese", "Burundian", "Cambodian",
+ "Cameroonian", "Canadian", "Cape Verdean", "Central African", "Chadian",
+ "Chilean", "Chinese", "Colombian", "Comorian", "Congolese", "Costa Rican",
+ "Croatian", "Cuban", "Cypriot", "Czech", "Danish", "Djiboutian", "Dominican",
+ "Dutch", "Ecuadorian", "Egyptian", "Emirati", "Equatorial Guinean",
+ "Eritrean", "Estonian", "Ethiopian", "Fijian", "Filipino", "Finnish", "French",
+ "Gabonese", "Gambian", "Georgian", "German", "Ghanaian", "Greek", "Grenadian",
+ "Guatemalan", "Guinean", "Guyanese", "Haitian", "Honduran", "Hungarian",
+ "Icelandic", "Indian", "Indonesian", "Iranian", "Iraqi", "Irish", "Israeli",
+ "Italian", "Ivorian", "Jamaican", "Japanese", "Jordanian", "Kazakh", "Kenyan",
+ "Kiribati", "Kuwaiti", "Kyrgyz", "Laotian", "Latvian", "Lebanese", "Liberian",
+ "Libyan", "Liechtenstein", "Lithuanian", "Luxembourgish", "Malagasy", "Malawian",
+ "Malaysian", "Maldivian", "Malian", "Maltese", "Marshallese", "Mauritanian",
+ "Mauritian", "Mexican", "Micronesian", "Moldovan", "Monacan", "Mongolian",
+ "Montenegrin", "Moroccan", "Mozambican", "Namibian", "Nauruan", "Nepalese",
+ "New Zealander", "Nicaraguan", "Nigerien", "Nigerian", "North Korean",
+ "North Macedonian", "Norwegian", "Omani", "Pakistani", "Palauan", "Palestinian",
+ "Panamanian", "Papua New Guinean", "Paraguayan", "Peruvian", "Polish", "Portuguese",
+ "Qatari", "Romanian", "Russian", "Rwandan", "Saint Lucian", "Salvadoran", "Samoan",
+ "Saudi Arabian", "Scottish", "Senegalese", "Serbian", "Seychellois", "Sierra Leonean",
+ "Singaporean", "Slovak", "Slovenian", "Solomon Islander", "Somali", "South African",
+ "South Korean", "South Sudanese", "Spanish", "Sri Lankan", "Sudanese", "Surinamese",
+ "Swazi", "Swedish", "Swiss", "Syrian", "Tajik", "Tanzanian", "Thai", "Timorese",
+ "Togolese", "Tongan", "Trinidadian", "Tunisian", "Turkish", "Turkmen", "Tuvaluan",
+ "Ugandan", "Ukrainian", "Uruguayan", "Uzbek", "Vanuatuan", "Venezuelan", "Vietnamese",
+ "Welsh", "Yemeni", "Zambian", "Zimbabwean"
+ );
+
+
+ public final String value;
+
+ /**
+ * Constructs a {@code Nationality}.
+ *
+ * @param nationality A valid Nationality.
+ */
+ public Nationality(String nationality) {
+ requireNonNull(nationality);
+ checkArgument(isValidNationality(nationality), MESSAGE_CONSTRAINTS);
+ this.value = capitalize(nationality);
+ }
+
+ /**
+ * Returns if Nationality is valid
+ */
+ public static boolean isValidNationality(String nationality) {
+ if (nationality == null) {
+ throw new NullPointerException(MESSAGE_CONSTRAINTS); // throw NullPointerException instead
+ }
+ return VALID_NATIONALITIES.stream()
+ .anyMatch(validNationality -> validNationality.equalsIgnoreCase(nationality));
+ }
+
+ /**
+ * Capitalises the first letter of the input
+ */
+ private static String capitalize(String nationality) {
+ // Convert to proper case (e.g., "american" -> "American")
+ String[] words = nationality.split(" ");
+ StringBuilder capitalizedNationality = new StringBuilder();
+ for (String word : words) {
+ if (capitalizedNationality.length() > 0) {
+ capitalizedNationality.append(" ");
+ }
+ capitalizedNationality.append(word.substring(0, 1).toUpperCase()).append(word.substring(1).toLowerCase());
+ }
+ return capitalizedNationality.toString();
+ }
+
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Nationality)) {
+ return false;
+ }
+
+ Nationality otherNationality = (Nationality) other;
+ return otherNationality.value.equals(value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Note.java b/src/main/java/seedu/address/model/person/Note.java
new file mode 100644
index 00000000000..e2dc094c007
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Note.java
@@ -0,0 +1,36 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Represents a Person's note in the address book.
+ * Guarantees: immutable; is always valid
+ */
+public class Note {
+ public final String value;
+
+ /**
+ * @param note
+ */
+ public Note(String note) {
+ requireNonNull(note);
+ value = note;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Note// instanceof handles nulls
+ && value.equals(((Note) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Nric.java b/src/main/java/seedu/address/model/person/Nric.java
new file mode 100644
index 00000000000..2bbb91eef63
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Nric.java
@@ -0,0 +1,59 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Person's nric in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidNric(String)}
+ */
+public class Nric {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "NRIC should start with S, T, F, or G, followed by 7 digits, and end with a capital letter.";
+ public static final String NRIC_VALIDATION_REGEX = "^[STFG]\\d{7}[A-Z]$";
+
+ public final String value;
+
+ /**
+ * Constructs an {@code Nric}
+ *
+ * @param nric A valid Nric.
+ */
+ public Nric(String nric) {
+ requireNonNull(nric);
+ checkArgument(isValidNric(nric), MESSAGE_CONSTRAINTS);
+ value = nric;
+ }
+
+ /**
+ * returns if a given string is a valid dob.
+ */
+ public static boolean isValidNric(String test) {
+ return test.matches(NRIC_VALIDATION_REGEX);
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Nric)) {
+ return false;
+ }
+
+ Nric otherNric = (Nric) other;
+ return value.equals(otherNric.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
index abe8c46b535..5b57630c3f7 100644
--- a/src/main/java/seedu/address/model/person/Person.java
+++ b/src/main/java/seedu/address/model/person/Person.java
@@ -2,10 +2,7 @@
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-import java.util.Collections;
-import java.util.HashSet;
import java.util.Objects;
-import java.util.Set;
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.model.tag.Tag;
@@ -20,21 +17,34 @@ public class Person {
private final Name name;
private final Phone phone;
private final Email email;
+ private final Nric nric;
// Data fields
+ private final Gender gender;
+ private final Dob dob;
+ private final DateOfJoining dateOfJoining;
+ private final Nationality nationality;
private final Address address;
- private final Set tags = new HashSet<>();
+ private final Note note;
+ private final Tag tag;
/**
* Every field must be present and not null.
*/
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
- requireAllNonNull(name, phone, email, address, tags);
+ public Person(Name name, Phone phone, Email email, Nric nric, Gender gender, Dob dob, DateOfJoining dateOfJoining,
+ Nationality nationality, Address address, Note note, Tag tag) {
+ requireAllNonNull(name, phone, email, gender, dob, dateOfJoining, nationality, address, tag);
this.name = name;
this.phone = phone;
this.email = email;
+ this.nric = nric;
+ this.gender = gender;
+ this.dob = dob;
+ this.dateOfJoining = dateOfJoining;
+ this.nationality = nationality;
this.address = address;
- this.tags.addAll(tags);
+ this.note = note;
+ this.tag = tag;
}
public Name getName() {
@@ -49,18 +59,43 @@ public Email getEmail() {
return email;
}
+ public Nric getNric() {
+ return nric;
+ }
+
+ public Gender getGender() {
+ return gender;
+ }
+
+ public Dob getDob() {
+ return dob;
+ }
+
+ public DateOfJoining getDateOfJoining() {
+ return dateOfJoining;
+ }
+
+ public Nationality getNationality() {
+ return nationality;
+ }
+
public Address getAddress() {
return address;
}
+ public Note getNote() {
+ return note;
+ }
+
/**
* Returns an immutable tag set, which throws {@code UnsupportedOperationException}
* if modification is attempted.
*/
- public Set getTags() {
- return Collections.unmodifiableSet(tags);
+ public Tag getTag() {
+ return tag;
}
+
/**
* Returns true if both persons have the same name.
* This defines a weaker notion of equality between two persons.
@@ -71,7 +106,7 @@ public boolean isSamePerson(Person otherPerson) {
}
return otherPerson != null
- && otherPerson.getName().equals(getName());
+ && otherPerson.getNric().equals(getNric());
}
/**
@@ -93,14 +128,19 @@ public boolean equals(Object other) {
return name.equals(otherPerson.name)
&& phone.equals(otherPerson.phone)
&& email.equals(otherPerson.email)
+ && nric.equals(otherPerson.nric)
+ && gender.equals(otherPerson.gender)
+ && dob.equals(otherPerson.dob)
+ && dateOfJoining.equals(otherPerson.dateOfJoining)
+ && nationality.equals(otherPerson.nationality)
&& address.equals(otherPerson.address)
- && tags.equals(otherPerson.tags);
+ && tag.equals(otherPerson.tag);
}
@Override
public int hashCode() {
// use this method for custom fields hashing instead of implementing your own
- return Objects.hash(name, phone, email, address, tags);
+ return Objects.hash(name, phone, email, nric, gender, dob, dateOfJoining, nationality, address, tag);
}
@Override
@@ -109,8 +149,13 @@ public String toString() {
.add("name", name)
.add("phone", phone)
.add("email", email)
+ .add("nric", nric)
+ .add("gender", gender)
+ .add("dob", dob)
+ .add("dateOfJoining", dateOfJoining)
+ .add("nationality", nationality)
.add("address", address)
- .add("tags", tags)
+ .add("tags", tag)
.toString();
}
diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/person/Phone.java
index d733f63d739..da5a1ef3266 100644
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ b/src/main/java/seedu/address/model/person/Phone.java
@@ -11,8 +11,8 @@ public class Phone {
public static final String MESSAGE_CONSTRAINTS =
- "Phone numbers should only contain numbers, and it should be at least 3 digits long";
- public static final String VALIDATION_REGEX = "\\d{3,}";
+ "Phone numbers must be exactly 8 digits long and start with 6, 8, or 9.";
+ public static final String VALIDATION_REGEX = "[689]\\d{7}";
public final String value;
/**
diff --git a/src/main/java/seedu/address/model/person/ProfileContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/ProfileContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..7e03a22bb00
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/ProfileContainsKeywordsPredicate.java
@@ -0,0 +1,50 @@
+package seedu.address.model.person;
+
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s full name or surname matches the keywords given
+ */
+public class ProfileContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ /**
+ * Constructs a ProfileContainsKeywordsPredicate with the given keywords.
+ *
+ * @param keywords The list of keywords to match against.
+ */
+ public ProfileContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords.stream()
+ .map(String::toLowerCase)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public boolean test(Person person) {
+ String fullName = person.getName().fullName.trim().toLowerCase();
+
+ for (String keyword : keywords) {
+ if (fullName.equals(keyword)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ProfileContainsKeywordsPredicate // instanceof handles nulls
+ && keywords.equals(((ProfileContainsKeywordsPredicate) other).keywords)); // state check
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("keywords", keywords).toString();
+ }
+}
+
diff --git a/src/main/java/seedu/address/model/tag/Department.java b/src/main/java/seedu/address/model/tag/Department.java
new file mode 100644
index 00000000000..04ace168d8c
--- /dev/null
+++ b/src/main/java/seedu/address/model/tag/Department.java
@@ -0,0 +1,192 @@
+package seedu.address.model.tag;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represents a Person's department in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidDepartment(String)}
+ */
+public class Department {
+ private static final String departments = "Human Resources, Finance, Accounting, Marketing, Sales, "
+ + "Customer Service, Information Technology, \n"
+ + "Research & Development, Operations, Legal, Supply Chain & Logistics, Procurement & Purchasing, "
+ + "Engineering, Quality Assurance, Product Management, Manufacturing, Public Relations, \n"
+ + "Corporate Communications, Compliance & Risk Management, Business Development, Data Science, "
+ + "Cybersecurity, Software Development, UX/UI Design, Artificial Intelligence & Machine Learning, \n"
+ + "Training & Development, Facilities Management, Administration, Health & Safety, "
+ + "Diversity, Equity & Inclusion.";
+
+ private static final String departmentsShortForm = "HR, CS, IT, R&D, SCM, Procurement, QA, PR, CorpComm, "
+ + "BizDev, DS, CyberSec, SD, UX&UI, AI&ML, T&D, FM, H&S, DEI.";
+
+ public static final String MESSAGE_CONSTRAINTS = "Department search must only contain alphabetic characters "
+ + "and the '&' symbol. It should not be blank.\n"
+ + "The search is flexible and supports:\n"
+ + "- Full department names (e.g., 'Human Resources')\n"
+ + "- Department short forms (e.g., 'HR' for Human Resources)\n"
+ + "- Partial matching with at least 3 consecutive letters (e.g., 'Fin' for Finance)\n"
+ + "\n"
+ + "Here is the list of Departments:\n"
+ + departments + "\n"
+ + "\n"
+ + "Here is the list of valid short forms:\n"
+ + departmentsShortForm;
+
+ private static final Set VALID_DEPARTMENTS = Set.of("Human Resources", "Finance", "Accounting",
+ "Marketing", "Sales", "Customer Service", "Information Technology",
+ "Research & Development", "Operations", "Legal",
+ "Supply Chain & Logistics", "Procurement & Purchasing", "Engineering",
+ "Quality Assurance", "Product Management", "Manufacturing",
+ "Public Relations", "Corporate Communications",
+ "Compliance & Risk Management", "Business Development", "Data Science",
+ "Cybersecurity", "Software Development", "UX/UI Design",
+ "Artificial Intelligence & Machine Learning", "Training & Development",
+ "Facilities Management", "Administration", "Health & Safety",
+ "Diversity, Equity & Inclusion");
+
+ private static final Map DEPARTMENTS_SHORT_FORM = Map.ofEntries(
+ Map.entry("Human Resources", "HR"),
+ Map.entry("Customer Service", "CS"),
+ Map.entry("Information Technology", "IT"),
+ Map.entry("Research & Development", "R&D"),
+ Map.entry("Supply Chain & Logistics", "SCM"),
+ Map.entry("Procurement & Purchasing", "Procurement"),
+ Map.entry("Quality Assurance", "QA"),
+ Map.entry("Public Relations", "PR"),
+ Map.entry("Corporate Communications", "CorpComm"),
+ Map.entry("Business Development", "BizDev"),
+ Map.entry("Data Science", "DS"),
+ Map.entry("Cybersecurity", "CyberSec"),
+ Map.entry("Software Development", "SD"),
+ Map.entry("UX/UI Design", "UX&UI"),
+ Map.entry("Artificial Intelligence & Machine Learning", "AI&ML"),
+ Map.entry("Training & Development", "T&D"),
+ Map.entry("Facilities Management", "FM"),
+ Map.entry("Health & Safety", "H&S"),
+ Map.entry("Diversity, Equity & Inclusion", "DEI")
+ );
+
+ public final String value;
+
+ /**
+ * Constructs an {@code Department}.
+ *
+ * @param department A valid department.
+ */
+ public Department(String department) {
+ requireNonNull(department);
+ checkArgument(isValidDepartment(department), MESSAGE_CONSTRAINTS);
+ value = mapInput(department);
+ }
+
+ private static String normalizeWhitespace(String input) {
+ return input.trim().replaceAll("\\s+", " ");
+ }
+
+ /**
+ * Returns true if a given string is a valid department.
+ */
+ public static boolean isValidDepartment(String department) {
+ String normalizedInput = normalizeWhitespace(department.toLowerCase());
+
+ boolean isDepartment = VALID_DEPARTMENTS.stream()
+ .map(validDepartment -> normalizeWhitespace(validDepartment.toLowerCase()))
+ .toList()
+ .contains(normalizedInput);
+
+ boolean isShortForm = DEPARTMENTS_SHORT_FORM.values().stream()
+ .map(shortForm -> normalizeWhitespace(shortForm.toLowerCase()))
+ .toList()
+ .contains(normalizedInput);
+
+ // Check for partial match (3 or more consecutive letters)
+ boolean isPartialMatch = false;
+ if (normalizedInput.length() >= 3) {
+ isPartialMatch = VALID_DEPARTMENTS.stream()
+ .anyMatch(validDepartment -> {
+ String normalizedDept = normalizeWhitespace(validDepartment.toLowerCase());
+ return normalizedDept.contains(normalizedInput);
+ });
+ }
+
+ return isDepartment || isShortForm || isPartialMatch;
+ }
+
+ /**
+ * Returns true if a given string is a valid department input.
+ */
+ public static boolean isValidDepartmentInput(String department) {
+ String normalizedInput = normalizeWhitespace(department.toLowerCase());
+
+ boolean isDepartment = VALID_DEPARTMENTS.stream()
+ .map(validDepartment -> normalizeWhitespace(validDepartment.toLowerCase()))
+ .toList()
+ .contains(normalizedInput);
+
+ boolean isShortForm = DEPARTMENTS_SHORT_FORM.values().stream()
+ .map(shortForm -> normalizeWhitespace(shortForm.toLowerCase()))
+ .toList()
+ .contains(normalizedInput);
+
+ return isDepartment || isShortForm;
+ }
+
+ /**
+ * Maps given string to a string in VALID_DEPARTMENTS
+ */
+ public static String mapInput(String department) {
+ String normalizedInput = normalizeWhitespace(department.toLowerCase());
+
+ for (String validDepartment : VALID_DEPARTMENTS) {
+ if (normalizeWhitespace(validDepartment.toLowerCase()).equals(normalizedInput)) {
+ return validDepartment;
+ }
+ }
+
+ for (Map.Entry departmentShortForm : DEPARTMENTS_SHORT_FORM.entrySet()) {
+ if (normalizeWhitespace(departmentShortForm.getValue().toLowerCase()).equals(normalizedInput)) {
+ return departmentShortForm.getKey();
+ }
+ }
+
+ throw new IllegalArgumentException("Invalid department: " + department);
+ }
+
+ /**
+ * Returns a map of all departments and their short forms.
+ */
+ public static Map getDepartmentsShortForm() {
+ return DEPARTMENTS_SHORT_FORM;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof seedu.address.model.tag.Department)) {
+ return false;
+ }
+
+ seedu.address.model.tag.Department otherDepartment = (seedu.address.model.tag.Department) other;
+ return value.equals(otherDepartment.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/model/tag/EmploymentType.java b/src/main/java/seedu/address/model/tag/EmploymentType.java
new file mode 100644
index 00000000000..83f346afbb7
--- /dev/null
+++ b/src/main/java/seedu/address/model/tag/EmploymentType.java
@@ -0,0 +1,83 @@
+package seedu.address.model.tag;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.util.Set;
+
+/**
+ * Represents a Person's employment type in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidEmploymentType(String)}
+ */
+public class EmploymentType {
+ private static final String employmentTypes = "Full-Time, Part-Time, Contract, Temporary, Internship, "
+ + "Freelance, Apprenticeship, Remote, Hybrid.";
+
+ public static final String MESSAGE_CONSTRAINTS = "Employment type must contain alphabetic characters, "
+ + "and the '-' symbol. It should not be blank. \n"
+ + "\n"
+ + "Here is the list of Employment Types: \n"
+ + employmentTypes;
+
+ private static final Set VALID_EMPLOYMENT_TYPES = Set.of("Full-Time", "Part-Time", "Contract",
+ "Temporary", "Internship", "Freelance", "Apprenticeship", "Remote", "Hybrid");
+
+ public final String value;
+
+ /**
+ * Constructs an {@code Employment Type}.
+ *
+ * @param employmentType A valid employment type.
+ */
+ public EmploymentType(String employmentType) {
+ requireNonNull(employmentType);
+ checkArgument(isValidEmploymentType(employmentType), MESSAGE_CONSTRAINTS);
+ this.value = VALID_EMPLOYMENT_TYPES.stream()
+ .filter(type -> type.equalsIgnoreCase(employmentType.trim()))
+ .findFirst()
+ .orElseThrow();
+ }
+
+ private static String normalizeWhitespace(String input) {
+ return input.trim().replaceAll("\\s+", " ");
+ }
+
+ /**
+ * Returns true if a given string is a valid employment type.
+ */
+ public static boolean isValidEmploymentType(String employmentType) {
+ String normalizedInput = normalizeWhitespace(employmentType.toLowerCase());
+
+ return VALID_EMPLOYMENT_TYPES.stream()
+ .map(validEmploymentType -> normalizeWhitespace(validEmploymentType.toLowerCase()))
+ .toList()
+ .contains(normalizedInput);
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof seedu.address.model.tag.EmploymentType)) {
+ return false;
+ }
+
+ seedu.address.model.tag.EmploymentType otherEmploymentType = (seedu.address.model.tag.EmploymentType) other;
+ return value.equals(otherEmploymentType.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/model/tag/JobTitle.java b/src/main/java/seedu/address/model/tag/JobTitle.java
new file mode 100644
index 00000000000..37a3c975c07
--- /dev/null
+++ b/src/main/java/seedu/address/model/tag/JobTitle.java
@@ -0,0 +1,158 @@
+package seedu.address.model.tag;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.util.Set;
+
+/**
+ * Represents a Person's job title in the address book.
+ * Guarantees: immutable; is valid as declared in {@link #isValidJobTitle(String)}
+ */
+public class JobTitle {
+ private static final String jobTitles = "Software Engineer, DevOps Engineer, Front-End Developer, "
+ + "Back-End Developer, Full-Stack Developer, Machine Learning Engineer, Data Engineer, \n"
+ + "Electrical Engineer, Mechanical Engineer, Civil Engineer, Robotics Engineer, Systems Engineer, "
+ + "Embedded Systems Developer, Test Automation Engineer, Aerospace Engineer, Chemical Engineer, \n"
+ + "Hardware Engineer, Biomedical Engineer, Data Analyst, Business Intelligence Analyst, "
+ + "Data Scientist, Financial Analyst, Quantitative Analyst, Risk Analyst, \n"
+ + "Market Research Analyst, Statistician, Data Architect, Database Administrator, "
+ + "Pricing Analyst, Operations Research Analyst, Product Manager, Associate Product Manager, \n"
+ + "Technical Product Manager, UX Designer, UI Designer, UX Researcher, Product Designer, "
+ + "Interaction Designer, Creative Director, Industrial Designer, Marketing Specialist, \n"
+ + "Digital Marketing Manager, SEO Specialist, Content Marketer, Growth Marketing Manager, "
+ + "Brand Manager, Sales Associate, Account Executive, Account Manager, \n"
+ + "Business Development Representative, Sales Manager, Partnership Manager, Social Media Manager, "
+ + "Customer Success Manager, Operations Manager, Chief Executive Officer, Chief Operating Officer, \n"
+ + "Chief Marketing Officer, Chief Technology Officer, Project Manager, Program Manager, "
+ + "Strategy Consultant, Business Consultant, General Manager, HR Coordinator, \n"
+ + "Recruitment Specialist, Office Manager, Executive Assistant, Administrative Assistant, "
+ + "Talent Acquisition Specialist, HR Generalist, Payroll Specialist, Customer Support Representative, \n"
+ + "Call Center Agent, IT Technician, Network Administrator, Systems Administrator, "
+ + "Cybersecurity Analyst, Information Security Analyst, IT Support Specialist, IT Project Manager, \n"
+ + "Cloud Engineer, Network Engineer, DevSecOps Engineer, Healthcare Administrator, "
+ + "Registered Nurse, Medical Assistant, Physical Therapist, Pharmacist, \n"
+ + "Clinical Research Coordinator, Mental Health Counselor, Medical Billing Specialist, Legal Advisor, "
+ + "Paralegal, Corporate Lawyer, Compliance Officer, Auditor, \n"
+ + "Accountant, Bookkeeper, Tax Analyst, Financial Planner, "
+ + "Investment Analyst, Electrician, Plumber, Welder, \n"
+ + "Construction Worker, Warehouse Manager, Logistics Coordinator, Supply Chain Manager, "
+ + "Procurement Specialist, Quality Assurance Tester, Field Service Technician, Graphic Designer, \n"
+ + "Content Writer, Copywriter, Technical Writer, Video Editor, "
+ + "Motion Graphics Designer, Photographer, Art Director, Animator, \n"
+ + "Editor, Journalist, Podcast Producer.";
+
+
+
+ public static final String MESSAGE_CONSTRAINTS = "Job title must contain alphabetic characters. \n"
+ + "It should not be blank. \n"
+ + "\n"
+ + "Here is the list of Job Titles: \n"
+ + jobTitles;
+
+ private static final Set VALID_JOB_TITLES = Set.of(
+ "Software Engineer", "DevOps Engineer", "Front-End Developer", "Back-End Developer",
+ "Full-Stack Developer", "Machine Learning Engineer", "Data Engineer", "Electrical Engineer",
+ "Mechanical Engineer", "Civil Engineer", "Robotics Engineer", "Systems Engineer",
+ "Embedded Systems Developer", "Test Automation Engineer", "Aerospace Engineer", "Chemical Engineer",
+ "Hardware Engineer", "Biomedical Engineer", "Data Analyst", "Business Intelligence Analyst",
+ "Data Scientist", "Financial Analyst", "Quantitative Analyst", "Risk Analyst",
+ "Market Research Analyst", "Statistician", "Data Architect", "Database Administrator",
+ "Pricing Analyst", "Operations Research Analyst", "Product Manager", "Associate Product Manager",
+ "Technical Product Manager", "UX Designer", "UI Designer", "UX Researcher", "Product Designer",
+ "Interaction Designer", "Creative Director", "Industrial Designer", "Marketing Specialist",
+ "Digital Marketing Manager", "SEO Specialist", "Content Marketer", "Growth Marketing Manager",
+ "Brand Manager", "Sales Associate", "Account Executive", "Account Manager",
+ "Business Development Representative", "Sales Manager", "Partnership Manager", "Social Media Manager",
+ "Customer Success Manager", "Operations Manager", "Chief Executive Officer", "Chief Operating Officer",
+ "Chief Marketing Officer", "Chief Technology Officer", "Project Manager", "Program Manager",
+ "Strategy Consultant", "Business Consultant", "General Manager", "HR Coordinator", "Recruitment Specialist",
+ "Office Manager", "Executive Assistant", "Administrative Assistant", "Talent Acquisition Specialist",
+ "HR Generalist", "Payroll Specialist", "Customer Support Representative", "Call Center Agent",
+ "IT Technician", "Network Administrator", "Systems Administrator", "Cybersecurity Analyst",
+ "Information Security Analyst", "IT Support Specialist", "IT Project Manager", "Cloud Engineer",
+ "Network Engineer", "DevSecOps Engineer", "Healthcare Administrator", "Registered Nurse",
+ "Medical Assistant", "Physical Therapist", "Pharmacist", "Clinical Research Coordinator",
+ "Mental Health Counselor", "Medical Billing Specialist", "Legal Advisor", "Paralegal",
+ "Corporate Lawyer", "Compliance Officer", "Auditor", "Accountant", "Bookkeeper",
+ "Tax Analyst", "Financial Planner", "Investment Analyst", "Electrician", "Plumber",
+ "Welder", "Construction Worker", "Warehouse Manager", "Logistics Coordinator",
+ "Supply Chain Manager", "Procurement Specialist", "Quality Assurance Tester",
+ "Field Service Technician", "Graphic Designer", "Content Writer", "Copywriter",
+ "Technical Writer", "Video Editor", "Motion Graphics Designer", "Photographer",
+ "Art Director", "Animator", "Editor", "Journalist", "Podcast Producer"
+ );
+
+
+ public final String value;
+
+ /**
+ * Constructs an {@code Job Title}.
+ *
+ * @param jobTitle A valid job title.
+ */
+ public JobTitle(String jobTitle) {
+ requireNonNull(jobTitle);
+ checkArgument(isValidJobTitle(jobTitle), MESSAGE_CONSTRAINTS);
+ value = mapInput(jobTitle);
+ }
+
+ private static String normalizeWhitespace(String input) {
+ return input.trim().replaceAll("\\s+", " ");
+ }
+
+ /**
+ * Returns true if a given string is a valid job title.
+ */
+ public static boolean isValidJobTitle(String jobTitle) {
+ String normalizedInput = normalizeWhitespace(jobTitle.toLowerCase());
+
+ return VALID_JOB_TITLES.stream()
+ .map(validJobTitle -> normalizeWhitespace(validJobTitle.toLowerCase()))
+ .toList()
+ .contains(normalizedInput);
+ }
+
+ /**
+ * Maps given string to a string in VALID_JOB_TITLES
+ */
+ public static String mapInput(String jobTitle) {
+ String normalizedInput = normalizeWhitespace(jobTitle.toLowerCase());
+
+ for (String validJobTitle : VALID_JOB_TITLES) {
+ if (normalizeWhitespace(validJobTitle.toLowerCase()).equals(normalizedInput)) {
+ return validJobTitle;
+ }
+ }
+
+ throw new IllegalArgumentException("Invalid job title: " + jobTitle);
+ }
+
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof seedu.address.model.tag.JobTitle)) {
+ return false;
+ }
+
+ seedu.address.model.tag.JobTitle otherJobTitle = (seedu.address.model.tag.JobTitle) other;
+ return value.equals(otherJobTitle.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/address/model/tag/Tag.java
index f1a0d4e233b..9c0cc0d8106 100644
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ b/src/main/java/seedu/address/model/tag/Tag.java
@@ -2,34 +2,56 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
+import static seedu.address.model.tag.Department.isValidDepartment;
+import static seedu.address.model.tag.EmploymentType.isValidEmploymentType;
+import static seedu.address.model.tag.JobTitle.isValidJobTitle;
+
+import java.util.Objects;
/**
* Represents a Tag in the address book.
- * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)}
+ * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String[])}
*/
public class Tag {
- public static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric";
+ public static final String MESSAGE_CONSTRAINTS = "Tags should contain 3 fields, separated with a '/' symbol: "
+ + "Department, Employment Type, Job Title";
public static final String VALIDATION_REGEX = "\\p{Alnum}+";
- public final String tagName;
+ private final Department department;
+
+ private final EmploymentType employmentType;
+
+ private final JobTitle jobTitle;
/**
* Constructs a {@code Tag}.
*
- * @param tagName A valid tag name.
+ * @param department A valid department name.
+ * @param employmentType A valid employment type.
+ * @param jobTitle A valid job title.
*/
- public Tag(String tagName) {
- requireNonNull(tagName);
- checkArgument(isValidTagName(tagName), MESSAGE_CONSTRAINTS);
- this.tagName = tagName;
+ public Tag(Department department, EmploymentType employmentType, JobTitle jobTitle) {
+ requireNonNull(department);
+ checkArgument(isValidDepartment(department.value), Department.MESSAGE_CONSTRAINTS);
+ this.department = department;
+
+ requireNonNull(employmentType);
+ checkArgument(isValidEmploymentType(employmentType.value), EmploymentType.MESSAGE_CONSTRAINTS);
+ this.employmentType = employmentType;
+
+ requireNonNull(jobTitle);
+ checkArgument(isValidJobTitle(jobTitle.value), JobTitle.MESSAGE_CONSTRAINTS);
+ this.jobTitle = jobTitle;
}
/**
* Returns true if a given string is a valid tag name.
*/
- public static boolean isValidTagName(String test) {
- return test.matches(VALIDATION_REGEX);
+ public static boolean isValidTagName(String[] tagList) {
+ return isValidDepartment(tagList[0])
+ && isValidEmploymentType(tagList[1])
+ && isValidJobTitle(tagList[2]);
}
@Override
@@ -44,19 +66,31 @@ public boolean equals(Object other) {
}
Tag otherTag = (Tag) other;
- return tagName.equals(otherTag.tagName);
+ return department.equals(otherTag.department)
+ && employmentType.equals(otherTag.employmentType)
+ && jobTitle.equals(otherTag.jobTitle);
}
@Override
public int hashCode() {
- return tagName.hashCode();
+ return Objects.hash(department, employmentType, jobTitle);
}
/**
* Format state as text for viewing.
*/
public String toString() {
- return '[' + tagName + ']';
+ return "[Department: " + department.value
+ + ", Employment Type: " + employmentType.value
+ + ", Job Title: " + jobTitle.value + ']';
+ }
+
+ public String[] getValue() {
+ String[] result = new String[3];
+ result[0] = department.value;
+ result[1] = employmentType.value;
+ result[2] = jobTitle.value;
+ return result;
}
}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
index 1806da4facf..1d1ce453840 100644
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java
@@ -1,42 +1,60 @@
package seedu.address.model.util;
-import java.util.Arrays;
-import java.util.Set;
-import java.util.stream.Collectors;
-
import seedu.address.model.AddressBook;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.person.Address;
+import seedu.address.model.person.DateOfJoining;
+import seedu.address.model.person.Dob;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Gender;
import seedu.address.model.person.Name;
+import seedu.address.model.person.Nationality;
+import seedu.address.model.person.Note;
+import seedu.address.model.person.Nric;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.tag.Department;
+import seedu.address.model.tag.EmploymentType;
+import seedu.address.model.tag.JobTitle;
import seedu.address.model.tag.Tag;
/**
* Contains utility methods for populating {@code AddressBook} with sample data.
*/
public class SampleDataUtil {
+ public static final Note EMPTY_NOTE = new Note("");
public static Person[] getSamplePersons() {
return new Person[] {
new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"),
- new Address("Blk 30 Geylang Street 29, #06-40"),
- getTagSet("friends")),
+ new Nric("S9019283Z"),
+ new Gender("Male"), new Dob("01-Oct-1990"), new DateOfJoining("12-Feb-2025"),
+ new Nationality("Singaporean"), new Address("Blk 30 Geylang Street 29, #06-40/101010"), EMPTY_NOTE,
+ getTag("Human Resources", "Full-Time", "HR Coordinator")),
new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"),
- new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"),
- getTagSet("colleagues", "friends")),
- new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"),
- new Address("Blk 11 Ang Mo Kio Street 74, #11-04"),
- getTagSet("neighbours")),
+ new Nric("T0119283Z"),
+ new Gender("Female"), new Dob("12-May-2001"), new DateOfJoining("12-Feb-2025"),
+ new Nationality("Singaporean"), new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18/192393"),
+ EMPTY_NOTE, getTag("Marketing", "Part-Time", "Marketing Specialist")),
+ new Person(new Name("Charlotte Olivia"), new Phone("93210283"), new Email("charlotte@example.com"),
+ new Nric("T1919183H"),
+ new Gender("Female"), new Dob("10-Dec-2019"), new DateOfJoining("12-Feb-2025"),
+ new Nationality("American"), new Address("Blk 11 Ang Mo Kio Street 74, #11-04/023456"), EMPTY_NOTE,
+ getTag("Information Technology", "Full-Time", "Software Engineer")),
new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"),
- new Address("Blk 436 Serangoon Gardens Street 26, #16-43"),
- getTagSet("family")),
+ new Nric("S9819013B"),
+ new Gender("Male"), new Dob("31-Oct-1998"), new DateOfJoining("12-Feb-2025"),
+ new Nationality("Chinese"), new Address("Blk 436 Serangoon Gardens Street 26, #16-43/203909"),
+ EMPTY_NOTE, getTag("Finance", "Internship", "Financial Analyst")),
new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"),
- new Address("Blk 47 Tampines Street 20, #17-35"),
- getTagSet("classmates")),
+ new Nric("T0219283W"),
+ new Gender("Male"), new Dob("10-Oct-2002"), new DateOfJoining("20-Aug-2024"),
+ new Nationality("Singaporean"), new Address("Blk 47 Tampines Street 20, #17-35/189002"), EMPTY_NOTE,
+ getTag("Information Technology", "Full-Time", "Data Analyst")),
new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"),
- new Address("Blk 45 Aljunied Street 85, #11-31"),
- getTagSet("colleagues"))
+ new Nric("S9919285A"),
+ new Gender("Male"), new Dob("30-Apr-1999"), new DateOfJoining("20-Aug-2024"),
+ new Nationality("Indonesian"), new Address("Blk 45 Aljunied Street 85, #11-31/067567"), EMPTY_NOTE,
+ getTag("Engineering", "Part-Time", "Electrical Engineer"))
};
}
@@ -49,12 +67,13 @@ public static ReadOnlyAddressBook getSampleAddressBook() {
}
/**
- * Returns a tag set containing the list of strings given.
+ * Returns a tag containing the list of strings given.
*/
- public static Set getTagSet(String... strings) {
- return Arrays.stream(strings)
- .map(Tag::new)
- .collect(Collectors.toSet());
+ public static Tag getTag(String department, String employmentType, String jobTitle) {
+ Department modelDepartment = new Department(department);
+ EmploymentType modelEmploymentType = new EmploymentType(employmentType);
+ JobTitle modelJobTitle = new JobTitle(jobTitle);
+ return new Tag(modelDepartment, modelEmploymentType, modelJobTitle);
}
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
index bd1ca0f56c8..c8d09eebbb3 100644
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
@@ -1,20 +1,23 @@
package seedu.address.storage;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.model.person.Address;
+import seedu.address.model.person.DateOfJoining;
+import seedu.address.model.person.Dob;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Gender;
import seedu.address.model.person.Name;
+import seedu.address.model.person.Nationality;
+import seedu.address.model.person.Note;
+import seedu.address.model.person.Nric;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.tag.Department;
+import seedu.address.model.tag.EmploymentType;
+import seedu.address.model.tag.JobTitle;
import seedu.address.model.tag.Tag;
/**
@@ -27,23 +30,37 @@ class JsonAdaptedPerson {
private final String name;
private final String phone;
private final String email;
+ private final String nric;
+ private final String gender;
+ private final String dob;
+ private final String dateOfJoining;
+ private final String nationality;
private final String address;
- private final List tags = new ArrayList<>();
+ private final String note;
+ private final String[] tag;
/**
* Constructs a {@code JsonAdaptedPerson} with the given person details.
*/
@JsonCreator
public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
- @JsonProperty("email") String email, @JsonProperty("address") String address,
- @JsonProperty("tags") List tags) {
+ @JsonProperty("email") String email, @JsonProperty("nric") String nric,
+ @JsonProperty("gender") String gender,
+ @JsonProperty("dob") String dob, @JsonProperty("dateOfJoining") String dateOfJoining,
+ @JsonProperty("nationality") String nationality,
+ @JsonProperty("address") String address, @JsonProperty("note") String note,
+ @JsonProperty("tag") String[] tag) {
this.name = name;
this.phone = phone;
this.email = email;
+ this.nric = nric;
+ this.gender = gender;
+ this.dob = dob;
+ this.dateOfJoining = dateOfJoining;
+ this.nationality = nationality;
this.address = address;
- if (tags != null) {
- this.tags.addAll(tags);
- }
+ this.note = note;
+ this.tag = tag;
}
/**
@@ -53,10 +70,14 @@ public JsonAdaptedPerson(Person source) {
name = source.getName().fullName;
phone = source.getPhone().value;
email = source.getEmail().value;
+ nric = source.getNric().value;
+ gender = source.getGender().value;
+ dob = source.getDob().value;
+ dateOfJoining = source.getDateOfJoining().value;
+ nationality = source.getNationality().value;
address = source.getAddress().value;
- tags.addAll(source.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList()));
+ note = source.getNote().value;
+ tag = source.getTag().getValue();
}
/**
@@ -65,11 +86,6 @@ public JsonAdaptedPerson(Person source) {
* @throws IllegalValueException if there were any data constraints violated in the adapted person.
*/
public Person toModelType() throws IllegalValueException {
- final List personTags = new ArrayList<>();
- for (JsonAdaptedTag tag : tags) {
- personTags.add(tag.toModelType());
- }
-
if (name == null) {
throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
}
@@ -94,16 +110,76 @@ public Person toModelType() throws IllegalValueException {
}
final Email modelEmail = new Email(email);
+ if (nric == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Nric.class.getSimpleName()));
+ }
+ if (!Nric.isValidNric(nric)) {
+ throw new IllegalValueException(Nric.MESSAGE_CONSTRAINTS);
+ }
+ final Nric modelNric = new Nric(nric);
+
+ if (gender == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Gender.class.getSimpleName()));
+ }
+ if (!Gender.isValidGender(gender)) {
+ throw new IllegalValueException(Gender.MESSAGE_CONSTRAINTS);
+ }
+ final Gender modelGender = new Gender(gender);
+
+ if (dob == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Dob.class.getSimpleName()));
+ }
+ if (!Dob.isValidDob(dob)) {
+ throw new IllegalValueException(Dob.MESSAGE_CONSTRAINTS);
+ }
+ final Dob modelDob = new Dob(dob);
+
+ if (dateOfJoining == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ DateOfJoining.class.getSimpleName()));
+ }
+ if (!DateOfJoining.isValidDate(dateOfJoining)) {
+ throw new IllegalValueException(DateOfJoining.MESSAGE_CONSTRAINTS);
+ }
+ final DateOfJoining modelDateOfJoining = new DateOfJoining(dateOfJoining);
+
+ if (nationality == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ Nationality.class.getSimpleName()));
+ }
+ if (!Nationality.isValidNationality(nationality)) {
+ throw new IllegalValueException(Nationality.MESSAGE_CONSTRAINTS);
+ }
+ final Nationality modelNationality = new Nationality(nationality);
+
if (address == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()));
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ Address.class.getSimpleName()));
}
if (!Address.isValidAddress(address)) {
throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS);
}
final Address modelAddress = new Address(address);
- final Set modelTags = new HashSet<>(personTags);
- return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags);
+ final Note modelNote = new Note(note);
+ /* if (note == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Note.class.getSimpleName()));
+ } */
+
+ if (tag == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ Tag.class.getSimpleName()));
+ }
+ if (!Tag.isValidTagName(tag)) {
+ throw new IllegalValueException(Tag.MESSAGE_CONSTRAINTS);
+ }
+ final Department department = new Department(tag[0]);
+ final EmploymentType employmentType = new EmploymentType(tag[1]);
+ final JobTitle jobTitle = new JobTitle(tag[2]);
+ final Tag modelTag = new Tag(department, employmentType, jobTitle);
+
+ return new Person(modelName, modelPhone, modelEmail, modelNric, modelGender, modelDob, modelDateOfJoining,
+ modelNationality, modelAddress, modelNote, modelTag);
}
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/seedu/address/storage/JsonAdaptedTag.java
index 0df22bdb754..9ca5bd89857 100644
--- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java
+++ b/src/main/java/seedu/address/storage/JsonAdaptedTag.java
@@ -4,6 +4,9 @@
import com.fasterxml.jackson.annotation.JsonValue;
import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.tag.Department;
+import seedu.address.model.tag.EmploymentType;
+import seedu.address.model.tag.JobTitle;
import seedu.address.model.tag.Tag;
/**
@@ -11,26 +14,26 @@
*/
class JsonAdaptedTag {
- private final String tagName;
+ private final String[] tag;
/**
* Constructs a {@code JsonAdaptedTag} with the given {@code tagName}.
*/
@JsonCreator
- public JsonAdaptedTag(String tagName) {
- this.tagName = tagName;
+ public JsonAdaptedTag(String[] tag) {
+ this.tag = tag;
}
/**
* Converts a given {@code Tag} into this class for Jackson use.
*/
public JsonAdaptedTag(Tag source) {
- tagName = source.tagName;
+ this.tag = source.getValue();
}
@JsonValue
- public String getTagName() {
- return tagName;
+ public String[] getTagName() {
+ return this.tag;
}
/**
@@ -39,10 +42,13 @@ public String getTagName() {
* @throws IllegalValueException if there were any data constraints violated in the adapted tag.
*/
public Tag toModelType() throws IllegalValueException {
- if (!Tag.isValidTagName(tagName)) {
+ if (!Tag.isValidTagName(this.tag)) {
throw new IllegalValueException(Tag.MESSAGE_CONSTRAINTS);
}
- return new Tag(tagName);
+ Department department = new Department(tag[0]);
+ EmploymentType employmentType = new EmploymentType(tag[1]);
+ JobTitle jobTitle = new JobTitle(tag[2]);
+ return new Tag(department, employmentType, jobTitle);
}
}
diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/address/ui/HelpWindow.java
index 3f16b2fcf26..5cc9df993ef 100644
--- a/src/main/java/seedu/address/ui/HelpWindow.java
+++ b/src/main/java/seedu/address/ui/HelpWindow.java
@@ -15,7 +15,7 @@
*/
public class HelpWindow extends UiPart {
- public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html";
+ public static final String USERGUIDE_URL = "https://ay2425s2-cs2103t-f14-2.github.io/tp/UserGuide.html";
public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL;
private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
diff --git a/src/main/java/seedu/address/ui/HomePersonCard.java b/src/main/java/seedu/address/ui/HomePersonCard.java
new file mode 100644
index 00000000000..96a3a7daea1
--- /dev/null
+++ b/src/main/java/seedu/address/ui/HomePersonCard.java
@@ -0,0 +1,74 @@
+package seedu.address.ui;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import seedu.address.model.person.Person;
+import seedu.address.model.tag.Tag;
+
+/**
+ * An UI component that displays information of a {@code Person} in the Home Screen.
+ */
+public class HomePersonCard extends UiPart {
+
+ private static final String FXML = "HomePersonCard.fxml";
+
+ public final Person person;
+
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private Label name;
+ @FXML
+ private Label id;
+ @FXML
+ private Label nric;
+ @FXML
+ private HBox tagBox;
+ @FXML
+ private FlowPane department;
+ @FXML
+ private FlowPane employmentType;
+ @FXML
+ private FlowPane jobTitle;
+
+ /**
+ * Creates a {@code HomePersonCard} with the given {@code Person} and index to display.
+ */
+ public HomePersonCard(Person person, int displayedIndex) {
+ super(FXML);
+ this.person = person;
+ id.setText(displayedIndex + ". ");
+ name.setText(person.getName().fullName);
+ nric.setText(person.getNric().value);
+
+ Tag tag = person.getTag();
+
+ if (tag != null) {
+ String[] tags = tag.getValue();
+ tagBox.getChildren().clear();
+ department.getChildren().clear();
+ department.getChildren().add(new Label("Department: " + tags[0]));
+ employmentType.getChildren().clear();
+ employmentType.getChildren().add(new Label("Employment Type: " + tags[1]));
+ jobTitle.getChildren().clear();
+ jobTitle.getChildren().add(new Label("Job Title: " + tags[2]));
+ tagBox.getChildren().addAll(department, employmentType, jobTitle);
+ }
+ }
+
+ public FlowPane getDepartment() {
+ return department;
+ }
+
+ public FlowPane getEmploymentType() {
+ return employmentType;
+ }
+
+ public FlowPane getJobTitle() {
+ return jobTitle;
+ }
+
+}
diff --git a/src/main/java/seedu/address/ui/HomePersonCardPanel.java b/src/main/java/seedu/address/ui/HomePersonCardPanel.java
new file mode 100644
index 00000000000..96fec182512
--- /dev/null
+++ b/src/main/java/seedu/address/ui/HomePersonCardPanel.java
@@ -0,0 +1,45 @@
+package seedu.address.ui;
+
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.Region;
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.model.person.Person;
+
+/**
+ * Panel containing list of persons in home page.
+ */
+public class HomePersonCardPanel extends UiPart {
+ private static final String FXML = "HomePersonCardPanel.fxml";
+ private final Logger logger = LogsCenter.getLogger(HomePersonCardPanel.class);
+
+ @FXML
+ private ListView homePersonListView;
+
+ /**
+ * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code HomePersonCard}.
+ */
+ public HomePersonCardPanel(ObservableList homePersonList) {
+ super(FXML);
+ homePersonListView.setItems(homePersonList);
+ homePersonListView.setCellFactory(listView -> new PersonListViewCell());
+ }
+
+ class PersonListViewCell extends ListCell {
+ @Override
+ protected void updateItem(Person person, boolean empty) {
+ super.updateItem(person, empty);
+
+ if (empty || person == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new HomePersonCard(person, getIndex() + 1).getRoot());
+ }
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java
index 79e74ef37c0..0509311320e 100644
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ b/src/main/java/seedu/address/ui/MainWindow.java
@@ -27,11 +27,15 @@ public class MainWindow extends UiPart {
private final Logger logger = LogsCenter.getLogger(getClass());
+ private boolean isDetailedView = false;
+
private Stage primaryStage;
private Logic logic;
// Independent Ui parts residing in this Ui container
+ private HomePersonCardPanel homePersonCardPanel;
private PersonListPanel personListPanel;
+ private PersonNoteListPanel personNoteListPanel;
private ResultDisplay resultDisplay;
private HelpWindow helpWindow;
@@ -41,9 +45,15 @@ public class MainWindow extends UiPart {
@FXML
private MenuItem helpMenuItem;
+ @FXML
+ private MenuItem homeMenuItem;
+
@FXML
private StackPane personListPanelPlaceholder;
+ @FXML
+ private StackPane homePersonCardPanelPlaceholder;
+
@FXML
private StackPane resultDisplayPlaceholder;
@@ -74,6 +84,7 @@ public Stage getPrimaryStage() {
private void setAccelerators() {
setAccelerator(helpMenuItem, KeyCombination.valueOf("F1"));
+ setAccelerator(homeMenuItem, KeyCombination.valueOf("F2"));
}
/**
@@ -110,8 +121,11 @@ private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) {
* Fills up all the placeholders of this window.
*/
void fillInnerParts() {
- personListPanel = new PersonListPanel(logic.getFilteredPersonList());
- personListPanelPlaceholder.getChildren().add(personListPanel.getRoot());
+ //personListPanel = new PersonListPanel(logic.getFilteredPersonList());
+ //personListPanelPlaceholder.getChildren().add(personListPanel.getRoot());
+
+ homePersonCardPanel = new HomePersonCardPanel(logic.getFilteredPersonList());
+ homePersonCardPanelPlaceholder.getChildren().add(homePersonCardPanel.getRoot());
resultDisplay = new ResultDisplay();
resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot());
@@ -123,6 +137,24 @@ void fillInnerParts() {
commandBoxPlaceholder.getChildren().add(commandBox.getRoot());
}
+ private void switchToPersonListView() {
+ isDetailedView = true;
+
+ homePersonCardPanelPlaceholder.getChildren().clear();
+
+ personListPanel = new PersonListPanel(logic.getFilteredPersonList());
+ homePersonCardPanelPlaceholder.getChildren().add(personListPanel.getRoot());
+ }
+
+ private void switchToPersonNoteView() {
+ isDetailedView = true;
+
+ homePersonCardPanelPlaceholder.getChildren().clear();
+
+ personNoteListPanel = new PersonNoteListPanel(logic.getFilteredPersonList());
+ homePersonCardPanelPlaceholder.getChildren().add(personNoteListPanel.getRoot());
+ }
+
/**
* Sets the default size based on {@code guiSettings}.
*/
@@ -147,6 +179,19 @@ public void handleHelp() {
}
}
+ /**
+ * Handles the action of navigating back to the home view.
+ */
+ @FXML
+ private void handleHome() {
+ logger.fine("Home button clicked - Navigating back to Home view.");
+ logic.showAllPersons(); // Reset the filtered list
+ homePersonCardPanelPlaceholder.getChildren().clear();
+ homePersonCardPanel = new HomePersonCardPanel(logic.getAddressBook().getPersonList());
+ homePersonCardPanelPlaceholder.getChildren().add(homePersonCardPanel.getRoot());
+ resultDisplay.setFeedbackToUser("Returned to Home");
+ }
+
void show() {
primaryStage.show();
}
@@ -167,6 +212,10 @@ public PersonListPanel getPersonListPanel() {
return personListPanel;
}
+ public HomePersonCardPanel getHomePersonCardPanel() {
+ return homePersonCardPanel;
+ }
+
/**
* Executes the command and returns the result.
*
@@ -186,6 +235,21 @@ private CommandResult executeCommand(String commandText) throws CommandException
handleExit();
}
+ if (commandResult.isHome()) {
+ handleHome();
+ }
+
+ if (commandText.toLowerCase().startsWith("view ") || commandText.toLowerCase().startsWith("list")
+ || commandText.toLowerCase().startsWith("edit ")) {
+ switchToPersonListView();
+ } else if (commandText.toLowerCase().startsWith("note ")) {
+ switchToPersonNoteView();
+ } else {
+ if (isDetailedView) {
+ handleMinimalView();
+ }
+ }
+
return commandResult;
} catch (CommandException | ParseException e) {
logger.info("An error occurred while executing command: " + commandText);
@@ -193,4 +257,17 @@ private CommandResult executeCommand(String commandText) throws CommandException
throw e;
}
}
+
+
+ private void handleMinimalView() {
+ isDetailedView = false;
+
+ homePersonCardPanelPlaceholder.getChildren().clear();
+
+ homePersonCardPanel = new HomePersonCardPanel(logic.getFilteredPersonList());
+ homePersonCardPanelPlaceholder.getChildren().add(homePersonCardPanel.getRoot());
+ }
+
+
}
+
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
index 094c42cda82..e25bed0ce28 100644
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ b/src/main/java/seedu/address/ui/PersonCard.java
@@ -1,13 +1,12 @@
package seedu.address.ui;
-import java.util.Comparator;
-
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import seedu.address.model.person.Person;
+import seedu.address.model.tag.Tag;
/**
* An UI component that displays information of a {@code Person}.
@@ -25,7 +24,8 @@ public class PersonCard extends UiPart {
*/
public final Person person;
-
+ @FXML
+ private Label note;
@FXML
private HBox cardPane;
@FXML
@@ -39,7 +39,23 @@ public class PersonCard extends UiPart {
@FXML
private Label email;
@FXML
- private FlowPane tags;
+ private Label nric;
+ @FXML
+ private Label gender;
+ @FXML
+ private Label dob;
+ @FXML
+ private Label dateOfJoining;
+ @FXML
+ private Label nationality;
+ @FXML
+ private HBox tagBox;
+ @FXML
+ private FlowPane department;
+ @FXML
+ private FlowPane employmentType;
+ @FXML
+ private FlowPane jobTitle;
/**
* Creates a {@code PersonCode} with the given {@code Person} and index to display.
@@ -51,9 +67,103 @@ public PersonCard(Person person, int displayedIndex) {
name.setText(person.getName().fullName);
phone.setText(person.getPhone().value);
address.setText(person.getAddress().value);
+ note.setText(person.getNote().value);
+ nric.setText(person.getNric().value);
+ gender.setText(person.getGender().value);
+ dob.setText(person.getDob().value);
+ dateOfJoining.setText(person.getDateOfJoining().value);
+ nationality.setText(person.getNationality().value);
email.setText(person.getEmail().value);
- person.getTags().stream()
- .sorted(Comparator.comparing(tag -> tag.tagName))
- .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+
+ Tag tag = person.getTag();
+
+ if (tag != null) {
+ String[] tags = tag.getValue();
+ tagBox.getChildren().clear();
+ department.getChildren().clear();
+ department.getChildren().add(new Label("Department: " + tags[0]));
+ employmentType.getChildren().clear();
+ employmentType.getChildren().add(new Label("Employment Type: " + tags[1]));
+ jobTitle.getChildren().clear();
+ jobTitle.getChildren().add(new Label("Job Title: " + tags[2]));
+ tagBox.getChildren().addAll(department, employmentType, jobTitle);
+ }
+ }
+
+ /**
+ * Creates a {@code PersonCode} with the given {@code Person} and index to display.
+ */
+ public PersonCard(Person person, int displayedIndex, boolean placeholder) {
+ super(FXML);
+ this.person = person;
+ id.setText(displayedIndex + ". ");
+ name.setText(person.getName().fullName);
+ note.setText(person.getNote().value);
+ phone.setVisible(false);
+ phone.setManaged(false);
+ phone.setPrefHeight(0);
+ phone.setMinHeight(0);
+ phone.setMaxHeight(0);
+ address.setVisible(false);
+ address.setManaged(false);
+ address.setPrefHeight(0);
+ address.setMinHeight(0);
+ address.setMaxHeight(0);
+ nric.setVisible(false);
+ nric.setManaged(false);
+ nric.setPrefHeight(0);
+ nric.setMinHeight(0);
+ nric.setMaxHeight(0);
+ gender.setVisible(false);
+ gender.setManaged(false);
+ gender.setPrefHeight(0);
+ gender.setMinHeight(0);
+ gender.setMaxHeight(0);
+ dob.setVisible(false);
+ dob.setManaged(false);
+ dob.setPrefHeight(0);
+ dob.setMinHeight(0);
+ dob.setMaxHeight(0);
+ dateOfJoining.setVisible(false);
+ dateOfJoining.setManaged(false);
+ dateOfJoining.setPrefHeight(0);
+ dateOfJoining.setMinHeight(0);
+ dateOfJoining.setMaxHeight(0);
+ nationality.setVisible(false);
+ nationality.setManaged(false);
+ nationality.setPrefHeight(0);
+ nationality.setMinHeight(0);
+ nationality.setMaxHeight(0);
+ email.setVisible(false);
+ email.setManaged(false);
+ email.setPrefHeight(0);
+ email.setMinHeight(0);
+ email.setMaxHeight(0);
+
+ Tag tag = person.getTag();
+
+ if (tag != null) {
+ String[] tags = tag.getValue();
+ tagBox.getChildren().clear();
+ department.getChildren().clear();
+ department.getChildren().add(new Label("Department: " + tags[0]));
+ employmentType.getChildren().clear();
+ employmentType.getChildren().add(new Label("Employment Type: " + tags[1]));
+ jobTitle.getChildren().clear();
+ jobTitle.getChildren().add(new Label("Job Title: " + tags[2]));
+ tagBox.getChildren().addAll(department, employmentType, jobTitle);
+ }
+ }
+
+ public FlowPane getDepartment() {
+ return department;
+ }
+
+ public FlowPane getEmploymentType() {
+ return employmentType;
+ }
+
+ public FlowPane getJobTitle() {
+ return jobTitle;
}
}
diff --git a/src/main/java/seedu/address/ui/PersonNoteCard.java b/src/main/java/seedu/address/ui/PersonNoteCard.java
new file mode 100644
index 00000000000..cca777c4a49
--- /dev/null
+++ b/src/main/java/seedu/address/ui/PersonNoteCard.java
@@ -0,0 +1,108 @@
+package seedu.address.ui;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import seedu.address.model.person.Person;
+import seedu.address.model.tag.Tag;
+
+/**
+ * An UI component that displays information of a {@code Person}.
+ */
+public class PersonNoteCard extends UiPart {
+
+ private static final String FXML = "PersonNoteCard.fxml";
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ public final Person person;
+ @FXML
+ private Label note;
+ @FXML
+ private Label name;
+ @FXML
+ private Label id;
+ @FXML
+ private Label nric;
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private HBox tagBox;
+ @FXML
+ private FlowPane department;
+ @FXML
+ private FlowPane employmentType;
+ @FXML
+ private FlowPane jobTitle;
+
+ /**
+ * Creates a {@code PersonCode} with the given {@code Person} and index to display.
+ */
+ public PersonNoteCard(Person person, int displayedIndex) {
+ super(FXML);
+ this.person = person;
+ id.setText(displayedIndex + ". ");
+ name.setText(person.getName().fullName);
+ note.setText(person.getNote().value);
+
+ Tag tag = person.getTag();
+
+ if (tag != null) {
+ String[] tags = tag.getValue();
+ tagBox.getChildren().clear();
+ department.getChildren().clear();
+ department.getChildren().add(new Label("Department: " + tags[0]));
+ employmentType.getChildren().clear();
+ employmentType.getChildren().add(new Label("Employment Type: " + tags[1]));
+ jobTitle.getChildren().clear();
+ jobTitle.getChildren().add(new Label("Job Title: " + tags[2]));
+ tagBox.getChildren().addAll(department, employmentType, jobTitle);
+ }
+ }
+
+ /**
+ * Creates a {@code PersonCode} with the given {@code Person} and index to display.
+ */
+ public PersonNoteCard(Person person, int displayedIndex, boolean placeholder) {
+ super(FXML);
+ this.person = person;
+ id.setText(displayedIndex + ". ");
+ name.setText(person.getName().fullName);
+ nric.setText(person.getNric().value);
+ note.setText(person.getNote().value);
+
+ Tag tag = person.getTag();
+
+ if (tag != null) {
+ String[] tags = tag.getValue();
+ tagBox.getChildren().clear();
+ department.getChildren().clear();
+ department.getChildren().add(new Label("Department: " + tags[0]));
+ employmentType.getChildren().clear();
+ employmentType.getChildren().add(new Label("Employment Type: " + tags[1]));
+ jobTitle.getChildren().clear();
+ jobTitle.getChildren().add(new Label("Job Title: " + tags[2]));
+ tagBox.getChildren().addAll(department, employmentType, jobTitle);
+ }
+ }
+
+ public FlowPane getDepartment() {
+ return department;
+ }
+
+ public FlowPane getEmploymentType() {
+ return employmentType;
+ }
+
+ public FlowPane getJobTitle() {
+ return jobTitle;
+ }
+}
diff --git a/src/main/java/seedu/address/ui/PersonNoteListPanel.java b/src/main/java/seedu/address/ui/PersonNoteListPanel.java
new file mode 100644
index 00000000000..3eccdc70206
--- /dev/null
+++ b/src/main/java/seedu/address/ui/PersonNoteListPanel.java
@@ -0,0 +1,50 @@
+package seedu.address.ui;
+
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.Region;
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.model.person.Person;
+
+
+/**
+ * Panel containing the list of persons
+ * */
+public class PersonNoteListPanel extends UiPart {
+ private static final String FXML = "PersonNoteListPanel.fxml";
+ private final Logger logger = LogsCenter.getLogger(PersonListPanel.class);
+
+ @FXML
+ private ListView noteListView;
+
+ /**
+ * Creates a {@code PersonNoteListPanel} with the given {@code ObservableList}.
+ */
+ public PersonNoteListPanel(ObservableList personList) {
+ super(FXML);
+ noteListView.setItems(personList);
+ noteListView.setCellFactory(listView -> new PersonNoteListViewCell());
+ }
+
+ /**
+ * Custom {@code ListCell} that displays only the note field of a {@code Person}.
+ */
+ class PersonNoteListViewCell extends ListCell {
+ @Override
+ protected void updateItem(Person person, boolean empty) {
+ super.updateItem(person, empty);
+
+ if (empty || person == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new PersonNoteCard(person, getIndex() + 1, true).getRoot());
+ }
+ }
+ }
+}
+
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
index 36e6b001cd8..85b95ff669e 100644
--- a/src/main/resources/view/DarkTheme.css
+++ b/src/main/resources/view/DarkTheme.css
@@ -121,6 +121,20 @@
}
.cell_big_label {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 17px;
+ -fx-text-fill: #010504;
+ -fx-padding: 2;
+}
+
+.cell_big_home_label {
+ -fx-font-family: "Segoe UI Light";
+ -fx-font-size: 23px;
+ -fx-text-fill: #010504;
+ -fx-padding: 2;
+}
+
+.cell_home_label {
-fx-font-family: "Segoe UI Semibold";
-fx-font-size: 16px;
-fx-text-fill: #010504;
@@ -337,16 +351,48 @@
-fx-background-radius: 0;
}
-#tags {
- -fx-hgap: 7;
- -fx-vgap: 3;
+#tagBox {
+ -fx-alignment: center-left;
+}
+
+#department {
+ -fx-hgap: 15;
+ -fx-vgap: 10;
+}
+
+#department .label {
+ -fx-text-fill: white;
+ -fx-background-color: #73acd5;
+ -fx-padding: 1 3 1 3;
+ -fx-border-radius: 2;
+ -fx-background-radius: 2;
+ -fx-font-size: 13;
+}
+
+#employmentType {
+ -fx-hgap: 15;
+ -fx-vgap: 10;
+}
+
+#employmentType .label {
+ -fx-text-fill: white;
+ -fx-background-color: #467cd6;
+ -fx-padding: 1 3 1 3;
+ -fx-border-radius: 2;
+ -fx-background-radius: 2;
+ -fx-font-size: 13;
+}
+
+#jobTitle {
+ -fx-hgap: 15;
+ -fx-vgap: 10;
}
-#tags .label {
+#jobTitle .label {
-fx-text-fill: white;
- -fx-background-color: #3e7b91;
+ -fx-background-color: #8f8d8d;
-fx-padding: 1 3 1 3;
-fx-border-radius: 2;
-fx-background-radius: 2;
- -fx-font-size: 11;
+ -fx-font-size: 13;
}
diff --git a/src/main/resources/view/HomePersonCard.fxml b/src/main/resources/view/HomePersonCard.fxml
new file mode 100644
index 00000000000..cf37e851682
--- /dev/null
+++ b/src/main/resources/view/HomePersonCard.fxml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/HomePersonCardPanel.fxml b/src/main/resources/view/HomePersonCardPanel.fxml
new file mode 100644
index 00000000000..181ce27cae0
--- /dev/null
+++ b/src/main/resources/view/HomePersonCardPanel.fxml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
index 7778f666a0a..0c1e97d82a5 100644
--- a/src/main/resources/view/MainWindow.fxml
+++ b/src/main/resources/view/MainWindow.fxml
@@ -12,7 +12,7 @@
+ title="HRelper" minWidth="450" minHeight="600" onCloseRequest="#handleExit">
@@ -31,6 +31,9 @@
+
@@ -40,17 +43,24 @@
+ minHeight="100" prefHeight="150" maxHeight="200">
+
+
+
+
+
+
+
-
+
@@ -58,3 +68,5 @@
+
+
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml
index 84e09833a87..0a81c8e7b72 100644
--- a/src/main/resources/view/PersonListCard.fxml
+++ b/src/main/resources/view/PersonListCard.fxml
@@ -27,10 +27,47 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PersonNoteCard.fxml b/src/main/resources/view/PersonNoteCard.fxml
new file mode 100644
index 00000000000..36235a8d4c2
--- /dev/null
+++ b/src/main/resources/view/PersonNoteCard.fxml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PersonNoteListPanel.fxml b/src/main/resources/view/PersonNoteListPanel.fxml
new file mode 100644
index 00000000000..ddf1525e1b5
--- /dev/null
+++ b/src/main/resources/view/PersonNoteListPanel.fxml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
index 6a4d2b7181c..37a080907f2 100644
--- a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
+++ b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
@@ -1,13 +1,13 @@
{
"persons": [ {
"name": "Valid Person",
- "phone": "9482424",
+ "phone": "94820424",
"email": "hans@example.com",
- "address": "4th street"
+ "address": "4th street/282828"
}, {
"name": "Person With Invalid Phone Field",
"phone": "948asdf2424",
"email": "hans@example.com",
- "address": "4th street"
+ "address": "4th street/200980"
} ]
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
index a7427fe7aa2..3fe26e8fdf5 100644
--- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
@@ -3,12 +3,25 @@
"name": "Alice Pauline",
"phone": "94351253",
"email": "alice@example.com",
- "address": "123, Jurong West Ave 6, #08-111",
- "tags": [ "friends" ]
+ "gender" : "Female",
+ "nric" : "S9134567A",
+ "dob" : "01-Oct-1991",
+ "dateOfJoining" : "15-Apr-2024",
+ "nationality" : "Singaporean",
+ "address": "123, Jurong West Ave 6, #08-111/101010",
+ "note": "",
+ "tag" : ["Human Resources", "Full-Time", "HR Coordinator"]
}, {
"name": "Alice Pauline",
"phone": "94351253",
"email": "pauline@example.com",
- "address": "4th street"
+ "nric" : "S9134567A",
+ "gender" : "Female",
+ "dob" : "01-Oct-1991",
+ "dateOfJoining" : "15-Apr-2024",
+ "nationality" : "Singaporean",
+ "address": "4th street/100100",
+ "note": "",
+ "tag" : ["Human Resources", "Full-Time", "HR Coordinator"]
} ]
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
index ad3f135ae42..95f554559e7 100644
--- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
@@ -3,6 +3,12 @@
"name": "Hans Muster",
"phone": "9482424",
"email": "invalid@email!3e",
- "address": "4th street"
+ "nric": "T0192847A",
+ "gender" : "Male",
+ "dob": "2020 01 01",
+ "dateOfJoining" : "01-Jan-2024",
+ "nationality" : "American",
+ "address": "4th street",
+ "tag" : ["Human Resources", "Full-Time", "HR Coordinator"]
} ]
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
index 72262099d35..593209cde03 100644
--- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
@@ -4,43 +4,85 @@
"name" : "Alice Pauline",
"phone" : "94351253",
"email" : "alice@example.com",
- "address" : "123, Jurong West Ave 6, #08-111",
- "tags" : [ "friends" ]
+ "nric" : "S9134567A",
+ "gender" : "Female",
+ "dob" : "01-Oct-1991",
+ "dateOfJoining" : "15-Apr-2024",
+ "nationality" : "Singaporean",
+ "address" : "123, Jurong West Ave 6, #08-111/101010",
+ "note" : "",
+ "tag" : ["Human Resources", "Full-Time", "HR Coordinator"]
}, {
"name" : "Benson Meier",
"phone" : "98765432",
"email" : "johnd@example.com",
- "address" : "311, Clementi Ave 2, #02-25",
- "tags" : [ "owesMoney", "friends" ]
+ "nric" : "T0134567B",
+ "gender" : "Male",
+ "dob" : "10-Mar-2001",
+ "dateOfJoining" : "15-Apr-2024",
+ "nationality" : "Singaporean",
+ "address" : "311, Clementi Ave 2, #02-25/202020",
+ "note" : "",
+ "tag" : ["Marketing", "Part-Time", "Marketing Specialist"]
}, {
"name" : "Carl Kurz",
"phone" : "95352563",
"email" : "heinz@example.com",
- "address" : "wall street",
- "tags" : [ ]
+ "nric" : "T0234568C",
+ "gender" : "Male",
+ "dob" : "20-Aug-2002",
+ "dateOfJoining" : "15-Apr-2024",
+ "nationality" : "American",
+ "address" : "wall street/010101",
+ "note" : "",
+ "tag" : ["Information Technology", "Full-Time", "Software Engineer"]
}, {
"name" : "Daniel Meier",
"phone" : "87652533",
"email" : "cornelia@example.com",
- "address" : "10th street",
- "tags" : [ "friends" ]
+ "nric" : "T0134569D",
+ "gender" : "Male",
+ "dob" : "19-Aug-2001",
+ "dateOfJoining" : "15-Apr-2024",
+ "nationality" : "American",
+ "address" : "10th street/020202",
+ "note" : "",
+ "tag" : ["Finance", "Internship", "Financial Analyst"]
}, {
"name" : "Elle Meyer",
- "phone" : "9482224",
+ "phone" : "94892224",
"email" : "werner@example.com",
- "address" : "michegan ave",
- "tags" : [ ]
+ "nric" : "T0234560E",
+ "gender" : "Female",
+ "dob" : "28-Dec-2002",
+ "dateOfJoining" : "15-Apr-2024",
+ "nationality" : "Indonesian",
+ "note" : "",
+ "address" : "michegan ave/030303",
+ "tag" : ["Information Technology", "Full-Time", "Data Analyst"]
}, {
"name" : "Fiona Kunz",
- "phone" : "9482427",
+ "phone" : "94802427",
"email" : "lydia@example.com",
- "address" : "little tokyo",
- "tags" : [ ]
+ "nric" : "T0435560F",
+ "gender" : "Female",
+ "dob" : "30-Feb-2004",
+ "dateOfJoining" : "01-Jan-2024",
+ "nationality" : "Singaporean",
+ "address" : "little tokyo/272727",
+ "note" : "",
+ "tag" : ["Information Technology", "Part-Time", "Data Analyst"]
}, {
"name" : "George Best",
- "phone" : "9482442",
+ "phone" : "94829442",
"email" : "anna@example.com",
- "address" : "4th street",
- "tags" : [ ]
+ "nric" : "T0435569G",
+ "gender" : "Male",
+ "dob" : "27-Sep-2004",
+ "dateOfJoining" : "01-Jan-2024",
+ "nationality" : "American",
+ "address" : "4th street/282828",
+ "note" : "",
+ "tag" : ["Engineering", "Part-Time", "Electrical Engineer"]
} ]
}
diff --git a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
index 1037548a9cd..142eba64f89 100644
--- a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
+++ b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
@@ -9,5 +9,5 @@
"z" : 99
}
},
- "addressBookFilePath" : "addressbook.json"
+ "addressBookFilePath" : "hrelper.json"
}
diff --git a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
index b819bed900a..5762cca48e2 100644
--- a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
+++ b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
@@ -7,5 +7,5 @@
"y" : 100
}
},
- "addressBookFilePath" : "addressbook.json"
+ "addressBookFilePath" : "hrelper.json"
}
diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java
index baf8ce336a2..9dc3e996002 100644
--- a/src/test/java/seedu/address/logic/LogicManagerTest.java
+++ b/src/test/java/seedu/address/logic/LogicManagerTest.java
@@ -4,9 +4,15 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.DATE_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.DOB_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.GENDER_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.NATIONALITY_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.NRIC_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUMAN_RESOURCE;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.AMY;
@@ -46,7 +52,7 @@ public class LogicManagerTest {
@BeforeEach
public void setUp() {
JsonAddressBookStorage addressBookStorage =
- new JsonAddressBookStorage(temporaryFolder.resolve("addressBook.json"));
+ new JsonAddressBookStorage(temporaryFolder.resolve("hrelper.json"));
JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("userPrefs.json"));
StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage);
logic = new LogicManager(model, storage);
@@ -67,7 +73,7 @@ public void execute_commandExecutionError_throwsCommandException() {
@Test
public void execute_validCommand_success() throws Exception {
String listCommand = ListCommand.COMMAND_WORD;
- assertCommandSuccess(listCommand, ListCommand.MESSAGE_SUCCESS, model);
+ assertCommandSuccess(listCommand, "No persons in the database currently.", model);
}
@Test
@@ -166,8 +172,10 @@ public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath)
// Triggers the saveAddressBook method by executing an add command
String addCommand = AddCommand.COMMAND_WORD + NAME_DESC_AMY + PHONE_DESC_AMY
- + EMAIL_DESC_AMY + ADDRESS_DESC_AMY;
- Person expectedPerson = new PersonBuilder(AMY).withTags().build();
+ + EMAIL_DESC_AMY + NRIC_DESC_AMY + GENDER_DESC_AMY + DOB_DESC_AMY + DATE_DESC_AMY
+ + NATIONALITY_DESC_AMY + ADDRESS_DESC_AMY + TAG_DESC_HUMAN_RESOURCE;
+
+ Person expectedPerson = new PersonBuilder(AMY).build();
ModelManager expectedModel = new ModelManager();
expectedModel.addPerson(expectedPerson);
assertCommandFailure(addCommand, CommandException.class, expectedMessage, expectedModel);
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
index 162a0c86031..a99f73df604 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
@@ -28,7 +28,7 @@ public void setUp() {
@Test
public void execute_newPerson_success() {
- Person validPerson = new PersonBuilder().build();
+ Person validPerson = new PersonBuilder().withNric("T1111111A").build();
Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
expectedModel.addPerson(validPerson);
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
index 90e8253f48e..18d6116ce4d 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
@@ -55,8 +55,8 @@ public void execute_duplicatePerson_throwsCommandException() {
@Test
public void equals() {
- Person alice = new PersonBuilder().withName("Alice").build();
- Person bob = new PersonBuilder().withName("Bob").build();
+ Person alice = new PersonBuilder().withNric("T0123456A").build();
+ Person bob = new PersonBuilder().withNric("T0654321A").build();
AddCommand addAliceCommand = new AddCommand(alice);
AddCommand addBobCommand = new AddCommand(bob);
diff --git a/src/test/java/seedu/address/logic/commands/CommandResultTest.java b/src/test/java/seedu/address/logic/commands/CommandResultTest.java
index 7b8c7cd4546..c5c3f0a52a7 100644
--- a/src/test/java/seedu/address/logic/commands/CommandResultTest.java
+++ b/src/test/java/seedu/address/logic/commands/CommandResultTest.java
@@ -14,7 +14,7 @@ public void equals() {
// same values -> returns true
assertTrue(commandResult.equals(new CommandResult("feedback")));
- assertTrue(commandResult.equals(new CommandResult("feedback", false, false)));
+ assertTrue(commandResult.equals(new CommandResult("feedback", false, false, false)));
// same object -> returns true
assertTrue(commandResult.equals(commandResult));
@@ -29,10 +29,10 @@ public void equals() {
assertFalse(commandResult.equals(new CommandResult("different")));
// different showHelp value -> returns false
- assertFalse(commandResult.equals(new CommandResult("feedback", true, false)));
+ assertFalse(commandResult.equals(new CommandResult("feedback", true, false, false)));
// different exit value -> returns false
- assertFalse(commandResult.equals(new CommandResult("feedback", false, true)));
+ assertFalse(commandResult.equals(new CommandResult("feedback", false, true, false)));
}
@Test
@@ -46,10 +46,10 @@ public void hashcode() {
assertNotEquals(commandResult.hashCode(), new CommandResult("different").hashCode());
// different showHelp value -> returns different hashcode
- assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", true, false).hashCode());
+ assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", true, false, false).hashCode());
// different exit value -> returns different hashcode
- assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false, true).hashCode());
+ assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false, true, false).hashCode());
}
@Test
@@ -57,7 +57,7 @@ public void toStringMethod() {
CommandResult commandResult = new CommandResult("feedback");
String expected = CommandResult.class.getCanonicalName() + "{feedbackToUser="
+ commandResult.getFeedbackToUser() + ", showHelp=" + commandResult.isShowHelp()
- + ", exit=" + commandResult.isExit() + "}";
+ + ", exit=" + commandResult.isExit() + ", isHome=" + commandResult.isHome() + "}";
assertEquals(expected, commandResult.toString());
}
}
diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
index 643a1d08069..08e086a4ab9 100644
--- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
+++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
@@ -3,8 +3,13 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DOB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GENDER;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NATIONALITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NRIC;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import static seedu.address.testutil.Assert.assertThrows;
@@ -26,16 +31,28 @@
*/
public class CommandTestUtil {
+ public static final String VALID_NOTE_AMY = "Like skiing.";
+ public static final String VALID_NOTE_BOB = "Favourite pastime: Eating";
public static final String VALID_NAME_AMY = "Amy Bee";
public static final String VALID_NAME_BOB = "Bob Choo";
- public static final String VALID_PHONE_AMY = "11111111";
- public static final String VALID_PHONE_BOB = "22222222";
+ public static final String VALID_PHONE_AMY = "91111111";
+ public static final String VALID_PHONE_BOB = "82222222";
public static final String VALID_EMAIL_AMY = "amy@example.com";
public static final String VALID_EMAIL_BOB = "bob@example.com";
- public static final String VALID_ADDRESS_AMY = "Block 312, Amy Street 1";
- public static final String VALID_ADDRESS_BOB = "Block 123, Bobby Street 3";
- public static final String VALID_TAG_HUSBAND = "husband";
- public static final String VALID_TAG_FRIEND = "friend";
+ public static final String VALID_NRIC_AMY = "T0435398Z";
+ public static final String VALID_NRIC_BOB = "T0293828G";
+ public static final String VALID_GENDER_AMY = "Female";
+ public static final String VALID_GENDER_BOB = "Male";
+ public static final String VALID_DOB_AMY = "01-Jan-2004";
+ public static final String VALID_DOB_BOB = "19-Nov-2002";
+ public static final String VALID_DATE_AMY = "10-Feb-2025";
+ public static final String VALID_DATE_BOB = "10-Jan-2025";
+ public static final String VALID_NATIONALITY_AMY = "Singaporean";
+ public static final String VALID_NATIONALITY_BOB = "American";
+ public static final String VALID_ADDRESS_AMY = "Block 312, Amy Street 1/191128";
+ public static final String VALID_ADDRESS_BOB = "Block 123, Bobby Street 3/010101";
+ public static final String VALID_TAG_HUMAN_RESOURCE = "Human Resources/Full-Time/HR Coordinator";
+ public static final String VALID_TAG_MARKETING = "Marketing/Part-Time/Marketing Specialist";
public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY;
public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB;
@@ -43,16 +60,31 @@ public class CommandTestUtil {
public static final String PHONE_DESC_BOB = " " + PREFIX_PHONE + VALID_PHONE_BOB;
public static final String EMAIL_DESC_AMY = " " + PREFIX_EMAIL + VALID_EMAIL_AMY;
public static final String EMAIL_DESC_BOB = " " + PREFIX_EMAIL + VALID_EMAIL_BOB;
+ public static final String NRIC_DESC_AMY = " " + PREFIX_NRIC + VALID_NRIC_AMY;
+ public static final String NRIC_DESC_BOB = " " + PREFIX_NRIC + VALID_NRIC_BOB;
+ public static final String GENDER_DESC_AMY = " " + PREFIX_GENDER + VALID_GENDER_AMY;
+ public static final String GENDER_DESC_BOB = " " + PREFIX_GENDER + VALID_GENDER_BOB;
+ public static final String DOB_DESC_AMY = " " + PREFIX_DOB + VALID_DOB_AMY;
+ public static final String DOB_DESC_BOB = " " + PREFIX_DOB + VALID_DOB_BOB;
+ public static final String DATE_DESC_AMY = " " + PREFIX_DATE + VALID_DATE_AMY;
+ public static final String DATE_DESC_BOB = " " + PREFIX_DATE + VALID_DATE_BOB;
+ public static final String NATIONALITY_DESC_AMY = " " + PREFIX_NATIONALITY + VALID_NATIONALITY_AMY;
+ public static final String NATIONALITY_DESC_BOB = " " + PREFIX_NATIONALITY + VALID_NATIONALITY_BOB;
public static final String ADDRESS_DESC_AMY = " " + PREFIX_ADDRESS + VALID_ADDRESS_AMY;
public static final String ADDRESS_DESC_BOB = " " + PREFIX_ADDRESS + VALID_ADDRESS_BOB;
- public static final String TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND;
- public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND;
+ public static final String TAG_DESC_HUMAN_RESOURCE = " " + PREFIX_TAG + VALID_TAG_HUMAN_RESOURCE;
+ public static final String TAG_DESC_MARKETING = " " + PREFIX_TAG + VALID_TAG_MARKETING;
public static final String INVALID_NAME_DESC = " " + PREFIX_NAME + "James&"; // '&' not allowed in names
public static final String INVALID_PHONE_DESC = " " + PREFIX_PHONE + "911a"; // 'a' not allowed in phones
public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol
+ public static final String INVALID_NRIC_DESC = " " + PREFIX_NRIC + "T02911a";
+ public static final String INVALID_GENDER_DESC = " " + PREFIX_GENDER + "test";
+ public static final String INVALID_DOB_DESC = " " + PREFIX_DOB + "10 Dec 2020";
+ public static final String INVALID_DATE_DESC = " " + PREFIX_DATE + "01.01-2020";
+ public static final String INVALID_NATIONALITY_DESC = " " + PREFIX_NATIONALITY + "singapore";
public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses
- public static final String INVALID_TAG_DESC = " " + PREFIX_TAG + "hubby*"; // '*' not allowed in tags
+ public static final String INVALID_TAG_DESC = " " + PREFIX_TAG + "Teaching/Part-Time/Teacher"; // invalid department
public static final String PREAMBLE_WHITESPACE = "\t \r \n";
public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble";
@@ -62,11 +94,15 @@ public class CommandTestUtil {
static {
DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
- .withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY)
- .withTags(VALID_TAG_FRIEND).build();
+ .withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY)
+ .withGender(VALID_GENDER_AMY).withDob(VALID_DOB_AMY).withDateOfJoining(VALID_DATE_AMY)
+ .withNationality(VALID_NATIONALITY_AMY).withAddress(VALID_ADDRESS_AMY)
+ .withTags(VALID_TAG_HUMAN_RESOURCE).build();
DESC_BOB = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
- .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB)
- .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
+ .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB)
+ .withGender(VALID_GENDER_BOB).withDob(VALID_DOB_BOB).withDateOfJoining(VALID_DATE_BOB)
+ .withNationality(VALID_NATIONALITY_BOB).withAddress(VALID_ADDRESS_BOB)
+ .withTags(VALID_TAG_MARKETING).build();
}
/**
@@ -74,8 +110,8 @@ public class CommandTestUtil {
* - the returned {@link CommandResult} matches {@code expectedCommandResult}
* - the {@code actualModel} matches {@code expectedModel}
*/
- public static void assertCommandSuccess(Command command, Model actualModel, CommandResult expectedCommandResult,
- Model expectedModel) {
+ public static void assertCommandSuccess(Command command, Model actualModel,
+ CommandResult expectedCommandResult, Model expectedModel) {
try {
CommandResult result = command.execute(actualModel);
assertEquals(expectedCommandResult, result);
diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
index 469dd97daa7..e6c5623102d 100644
--- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
@@ -7,14 +7,17 @@
import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_MARKETING;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
+import static seedu.address.logic.commands.EditCommand.MESSAGE_NOT_EDITED;
import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import java.util.Arrays;
+
import org.junit.jupiter.api.Test;
import seedu.address.commons.core.index.Index;
@@ -25,6 +28,7 @@
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
import seedu.address.model.person.Person;
+import seedu.address.model.person.ProfileContainsKeywordsPredicate;
import seedu.address.testutil.EditPersonDescriptorBuilder;
import seedu.address.testutil.PersonBuilder;
@@ -46,6 +50,11 @@ public void execute_allFieldsSpecifiedUnfilteredList_success() {
Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
+ ProfileContainsKeywordsPredicate predicate = new ProfileContainsKeywordsPredicate(
+ Arrays.asList((editedPerson.getName().toString())));
+
+ expectedModel.updateFilteredPersonList(predicate);
+
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@@ -56,10 +65,10 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() {
PersonBuilder personInList = new PersonBuilder(lastPerson);
Person editedPerson = personInList.withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withTags(VALID_TAG_HUSBAND).build();
+ .withTags(VALID_TAG_MARKETING).build();
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
- .withPhone(VALID_PHONE_BOB).withTags(VALID_TAG_HUSBAND).build();
+ .withPhone(VALID_PHONE_BOB).withTags(VALID_TAG_MARKETING).build();
EditCommand editCommand = new EditCommand(indexLastPerson, descriptor);
String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
@@ -67,19 +76,20 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() {
Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
expectedModel.setPerson(lastPerson, editedPerson);
+ ProfileContainsKeywordsPredicate predicate = new ProfileContainsKeywordsPredicate(
+ Arrays.asList((editedPerson.getName().toString())));
+
+ expectedModel.updateFilteredPersonList(predicate);
+
+
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@Test
- public void execute_noFieldSpecifiedUnfilteredList_success() {
+ public void execute_noFieldSpecifiedUnfilteredList_failure() {
EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, new EditPersonDescriptor());
- Person editedPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
-
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
-
- assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
+ assertCommandFailure(editCommand, model, MESSAGE_NOT_EDITED);
}
@Test
@@ -96,6 +106,11 @@ public void execute_filteredList_success() {
Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
+ ProfileContainsKeywordsPredicate predicate = new ProfileContainsKeywordsPredicate(
+ Arrays.asList((editedPerson.getName().toString())));
+
+ expectedModel.updateFilteredPersonList(predicate);
+
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@@ -103,22 +118,25 @@ public void execute_filteredList_success() {
public void execute_duplicatePersonUnfilteredList_failure() {
Person firstPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(firstPerson).build();
- EditCommand editCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor);
+ EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor);
- assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON);
+ assertCommandFailure(editCommand, model, EditCommand.MESSAGE_NOT_CHANGED);
}
+ /*
@Test
public void execute_duplicatePersonFilteredList_failure() {
showPersonAtIndex(model, INDEX_FIRST_PERSON);
// edit person in filtered list into a duplicate in address book
Person personInList = model.getAddressBook().getPersonList().get(INDEX_SECOND_PERSON.getZeroBased());
+
EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON,
new EditPersonDescriptorBuilder(personInList).build());
- assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON);
+ assertCommandFailure(editCommand, model, EditCommand.MESSAGE_NOT_CHANGED);
}
+ */
@Test
public void execute_invalidPersonIndexUnfilteredList_failure() {
diff --git a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java b/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
index b17c1f3d5c2..82cc5763b95 100644
--- a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
@@ -6,10 +6,14 @@
import static seedu.address.logic.commands.CommandTestUtil.DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DATE_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DOB_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GENDER_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NATIONALITY_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_MARKETING;
import org.junit.jupiter.api.Test;
@@ -48,12 +52,28 @@ public void equals() {
editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withEmail(VALID_EMAIL_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
+ // different gender -> returns false
+ editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withGender(VALID_GENDER_BOB).build();
+ assertFalse(DESC_AMY.equals(editedAmy));
+
+ // different dob -> returns false
+ editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withDob(VALID_DOB_BOB).build();
+ assertFalse(DESC_AMY.equals(editedAmy));
+
+ // different dateOfJoining -> returns false
+ editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withDateOfJoining(VALID_DATE_BOB).build();
+ assertFalse(DESC_AMY.equals(editedAmy));
+
+ // different nationality -> returns false
+ editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withNationality(VALID_NATIONALITY_BOB).build();
+ assertFalse(DESC_AMY.equals(editedAmy));
+
// different address -> returns false
editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withAddress(VALID_ADDRESS_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
// different tags -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withTags(VALID_TAG_HUSBAND).build();
+ editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withTags(VALID_TAG_MARKETING).build();
assertFalse(DESC_AMY.equals(editedAmy));
}
@@ -63,9 +83,14 @@ public void toStringMethod() {
String expected = EditPersonDescriptor.class.getCanonicalName() + "{name="
+ editPersonDescriptor.getName().orElse(null) + ", phone="
+ editPersonDescriptor.getPhone().orElse(null) + ", email="
- + editPersonDescriptor.getEmail().orElse(null) + ", address="
- + editPersonDescriptor.getAddress().orElse(null) + ", tags="
- + editPersonDescriptor.getTags().orElse(null) + "}";
+ + editPersonDescriptor.getEmail().orElse(null) + ", gender="
+ + editPersonDescriptor.getGender().orElse(null) + ", dob="
+ + editPersonDescriptor.getDob().orElse(null) + ", dateOfJoining="
+ + editPersonDescriptor.getDateOfJoining().orElse(null) + ", nationality="
+ + editPersonDescriptor.getNationality().orElse(null) + ", address="
+ + editPersonDescriptor.getNote().orElse(null) + ", note="
+ + editPersonDescriptor.getAddress().orElse(null) + ", tag="
+ + editPersonDescriptor.getTag().orElse(null) + "}";
assertEquals(expected, editPersonDescriptor.toString());
}
}
diff --git a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java b/src/test/java/seedu/address/logic/commands/ExitCommandTest.java
index 9533c473875..a573f42f11b 100644
--- a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ExitCommandTest.java
@@ -14,7 +14,7 @@ public class ExitCommandTest {
@Test
public void execute_exit_success() {
- CommandResult expectedCommandResult = new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
+ CommandResult expectedCommandResult = new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true, false);
assertCommandSuccess(new ExitCommand(), model, expectedCommandResult, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/FindByDepartmentCommandTest.java b/src/test/java/seedu/address/logic/commands/FindByDepartmentCommandTest.java
new file mode 100644
index 00000000000..4a6b6f7790f
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FindByDepartmentCommandTest.java
@@ -0,0 +1,64 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.person.DepartmentContainsKeywordPredicate;
+
+public class FindByDepartmentCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void equals() {
+ DepartmentContainsKeywordPredicate firstPredicate =
+ new DepartmentContainsKeywordPredicate("Human Resources");
+ DepartmentContainsKeywordPredicate secondPredicate =
+ new DepartmentContainsKeywordPredicate("Finance");
+
+ FindByDepartmentCommand findFirstCommand = new FindByDepartmentCommand(firstPredicate);
+ FindByDepartmentCommand findSecondCommand = new FindByDepartmentCommand(secondPredicate);
+
+ assertTrue(findFirstCommand.equals(findFirstCommand));
+ FindByDepartmentCommand findFirstCommandCopy = new FindByDepartmentCommand(firstPredicate);
+ assertTrue(findFirstCommand.equals(findFirstCommandCopy));
+ assertFalse(findFirstCommand.equals(1));
+ assertFalse(findFirstCommand.equals(null));
+ assertFalse(findFirstCommand.equals(findSecondCommand));
+ }
+
+ @Test
+ public void execute_noDepartment_foundNoPersons() {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
+ DepartmentContainsKeywordPredicate predicate = preparePredicate("UnknownDept");
+ FindByDepartmentCommand command = new FindByDepartmentCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Collections.emptyList(), model.getFilteredPersonList());
+ }
+
+ // @Test
+ // public void execute_multipleDepartments_multiplePersonsFound() {
+ // String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
+ // DepartmentContainsKeywordPredicate predicate = preparePredicate("HR Finance");
+ // FindByDepartmentCommand command = new FindByDepartmentCommand(predicate);
+ // expectedModel.updateFilteredPersonList(predicate);
+ // assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ // assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList());
+ // }
+
+ private DepartmentContainsKeywordPredicate preparePredicate(String userInput) {
+ return new DepartmentContainsKeywordPredicate(userInput.trim());
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/FindByEmploymentTypeCommandTest.java b/src/test/java/seedu/address/logic/commands/FindByEmploymentTypeCommandTest.java
new file mode 100644
index 00000000000..4b16febed14
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FindByEmploymentTypeCommandTest.java
@@ -0,0 +1,64 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.person.EmploymentTypeContainsKeywordPredicate;
+
+public class FindByEmploymentTypeCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void equals() {
+ EmploymentTypeContainsKeywordPredicate firstPredicate =
+ new EmploymentTypeContainsKeywordPredicate("Full-time");
+ EmploymentTypeContainsKeywordPredicate secondPredicate =
+ new EmploymentTypeContainsKeywordPredicate("Part-time");
+
+ FindByEmploymentTypeCommand findFirstCommand = new FindByEmploymentTypeCommand(firstPredicate);
+ FindByEmploymentTypeCommand findSecondCommand = new FindByEmploymentTypeCommand(secondPredicate);
+
+ assertTrue(findFirstCommand.equals(findFirstCommand));
+ FindByEmploymentTypeCommand findFirstCommandCopy = new FindByEmploymentTypeCommand(firstPredicate);
+ assertTrue(findFirstCommand.equals(findFirstCommandCopy));
+ assertFalse(findFirstCommand.equals(1));
+ assertFalse(findFirstCommand.equals(null));
+ assertFalse(findFirstCommand.equals(findSecondCommand));
+ }
+
+ @Test
+ public void execute_noEmploymentType_foundNoPersons() {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
+ EmploymentTypeContainsKeywordPredicate predicate = preparePredicate("UnknownEmploymentType");
+ FindByEmploymentTypeCommand command = new FindByEmploymentTypeCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Collections.emptyList(), model.getFilteredPersonList());
+ }
+
+ // @Test
+ // public void execute_multipleEmploymentTypes_multiplePersonsFound() {
+ // String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
+ // EmploymentTypeContainsKeywordPredicate predicate = preparePredicate("Full-time");
+ // FindByEmploymentTypeCommand command = new FindByEmploymentTypeCommand(predicate);
+ // expectedModel.updateFilteredPersonList(predicate);
+ // assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ // assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList());
+ // }
+
+ private EmploymentTypeContainsKeywordPredicate preparePredicate(String userInput) {
+ return new EmploymentTypeContainsKeywordPredicate(userInput.trim());
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/FindByJobTitleCommandTest.java b/src/test/java/seedu/address/logic/commands/FindByJobTitleCommandTest.java
new file mode 100644
index 00000000000..23ffebb9fd6
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FindByJobTitleCommandTest.java
@@ -0,0 +1,64 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.person.JobTitleContainsKeywordPredicate;
+
+public class FindByJobTitleCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void equals() {
+ JobTitleContainsKeywordPredicate firstPredicate =
+ new JobTitleContainsKeywordPredicate("Engineer");
+ JobTitleContainsKeywordPredicate secondPredicate =
+ new JobTitleContainsKeywordPredicate("Manager");
+
+ FindByJobTitleCommand findFirstCommand = new FindByJobTitleCommand(firstPredicate);
+ FindByJobTitleCommand findSecondCommand = new FindByJobTitleCommand(secondPredicate);
+
+ assertTrue(findFirstCommand.equals(findFirstCommand));
+ FindByJobTitleCommand findFirstCommandCopy = new FindByJobTitleCommand(firstPredicate);
+ assertTrue(findFirstCommand.equals(findFirstCommandCopy));
+ assertFalse(findFirstCommand.equals(1));
+ assertFalse(findFirstCommand.equals(null));
+ assertFalse(findFirstCommand.equals(findSecondCommand));
+ }
+
+ @Test
+ public void execute_noJobTitle_foundNoPersons() {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
+ JobTitleContainsKeywordPredicate predicate = preparePredicate("CEO");
+ FindByJobTitleCommand command = new FindByJobTitleCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Collections.emptyList(), model.getFilteredPersonList());
+ }
+
+ // @Test
+ // public void execute_multipleJobTitles_multiplePersonsFound() {
+ // String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
+ // JobTitleContainsKeywordPredicate predicate = preparePredicate("Engineer");
+ // FindByJobTitleCommand command = new FindByJobTitleCommand(predicate);
+ // expectedModel.updateFilteredPersonList(predicate);
+ // assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ // assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList());
+ // }
+
+ private JobTitleContainsKeywordPredicate preparePredicate(String userInput) {
+ return new JobTitleContainsKeywordPredicate(userInput.trim());
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
index b8b7dbba91a..76bab2c0ec5 100644
--- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
@@ -1,91 +1,26 @@
package seedu.address.logic.commands;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.CARL;
-import static seedu.address.testutil.TypicalPersons.ELLE;
-import static seedu.address.testutil.TypicalPersons.FIONA;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
-
-import java.util.Arrays;
-import java.util.Collections;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import org.junit.jupiter.api.Test;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-/**
- * Contains integration tests (interaction with the Model) for {@code FindCommand}.
- */
public class FindCommandTest {
- private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
- private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
-
- @Test
- public void equals() {
- NameContainsKeywordsPredicate firstPredicate =
- new NameContainsKeywordsPredicate(Collections.singletonList("first"));
- NameContainsKeywordsPredicate secondPredicate =
- new NameContainsKeywordsPredicate(Collections.singletonList("second"));
-
- FindCommand findFirstCommand = new FindCommand(firstPredicate);
- FindCommand findSecondCommand = new FindCommand(secondPredicate);
-
- // same object -> returns true
- assertTrue(findFirstCommand.equals(findFirstCommand));
+ public static final String ERROR_MESSAGE = "Try using 'findByDepartment', "
+ + "'findByEmploymentType', or 'findByJobTitle' instead.";
- // same values -> returns true
- FindCommand findFirstCommandCopy = new FindCommand(firstPredicate);
- assertTrue(findFirstCommand.equals(findFirstCommandCopy));
-
- // different types -> returns false
- assertFalse(findFirstCommand.equals(1));
-
- // null -> returns false
- assertFalse(findFirstCommand.equals(null));
-
- // different person -> returns false
- assertFalse(findFirstCommand.equals(findSecondCommand));
- }
+ private Model model = new ModelManager();
@Test
- public void execute_zeroKeywords_noPersonFound() {
- String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
- NameContainsKeywordsPredicate predicate = preparePredicate(" ");
- FindCommand command = new FindCommand(predicate);
- expectedModel.updateFilteredPersonList(predicate);
- assertCommandSuccess(command, model, expectedMessage, expectedModel);
- assertEquals(Collections.emptyList(), model.getFilteredPersonList());
- }
-
- @Test
- public void execute_multipleKeywords_multiplePersonsFound() {
- String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
- NameContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz");
- FindCommand command = new FindCommand(predicate);
- expectedModel.updateFilteredPersonList(predicate);
- assertCommandSuccess(command, model, expectedMessage, expectedModel);
- assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList());
- }
-
- @Test
- public void toStringMethod() {
- NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Arrays.asList("keyword"));
- FindCommand findCommand = new FindCommand(predicate);
- String expected = FindCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
- assertEquals(expected, findCommand.toString());
- }
-
- /**
- * Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}.
- */
- private NameContainsKeywordsPredicate preparePredicate(String userInput) {
- return new NameContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+")));
+ public void execute_invalidCommand_showsErrorMessage() {
+ // Create the FindCommand and execute it
+ FindCommand command = new FindCommand();
+ String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, ERROR_MESSAGE);
+ // Execute the command and check the message
+ CommandResult result = command.execute(model);
+ assertEquals(expectedMessage, result.getFeedbackToUser());
}
}
diff --git a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java b/src/test/java/seedu/address/logic/commands/HelpCommandTest.java
index 4904fc4352e..3b35c387c4c 100644
--- a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/HelpCommandTest.java
@@ -14,7 +14,7 @@ public class HelpCommandTest {
@Test
public void execute_help_success() {
- CommandResult expectedCommandResult = new CommandResult(SHOWING_HELP_MESSAGE, true, false);
+ CommandResult expectedCommandResult = new CommandResult(SHOWING_HELP_MESSAGE, true, false, false);
assertCommandSuccess(new HelpCommand(), model, expectedCommandResult, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/NoteCommandTest.java b/src/test/java/seedu/address/logic/commands/NoteCommandTest.java
new file mode 100644
index 00000000000..48cf9c57964
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/NoteCommandTest.java
@@ -0,0 +1,119 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NOTE_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NOTE_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
+import seedu.address.model.AddressBook;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.person.Note;
+import seedu.address.model.person.Person;
+import seedu.address.testutil.PersonBuilder;
+
+/**
+ * Contains integration tests (interaction with the Model) and unit tests for RemarkCommand.
+ */
+public class NoteCommandTest {
+ private static final String NOTE_STUB = "Some remark";
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_addNoteUnfilteredList_success() {
+ Person firstPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
+ Person editedPerson = new PersonBuilder(firstPerson).withNote(NOTE_STUB).build();
+
+ NoteCommand noteCommand = new NoteCommand(INDEX_FIRST_PERSON, new Note(editedPerson.getNote().value));
+
+ String expectedMessage = NoteCommand.MESSAGE_ADD_NOTE_SUCCESS + " Name: " + editedPerson.getName().toString()
+ + " Nric: " + editedPerson.getNric().toString() + " Note: " + editedPerson.getNote().toString();
+
+ Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
+ expectedModel.setPerson(firstPerson, editedPerson);
+
+ assertCommandSuccess(noteCommand, model, expectedMessage, model);
+ }
+
+ @Test
+ public void execute_filteredList_success() {
+ showPersonAtIndex(model, INDEX_FIRST_PERSON);
+
+ Person firstPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
+ Person editedPerson = new PersonBuilder(model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()))
+ .withNote(NOTE_STUB).build();
+
+ NoteCommand noteCommand = new NoteCommand(INDEX_FIRST_PERSON, new Note(editedPerson.getNote().value));
+
+ String expectedMessage = NoteCommand.MESSAGE_ADD_NOTE_SUCCESS + " Name: " + editedPerson.getName().toString()
+ + " Nric: " + editedPerson.getNric().toString() + " Note: " + editedPerson.getNote().toString();
+
+ Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
+ expectedModel.setPerson(firstPerson, editedPerson);
+
+ assertCommandSuccess(noteCommand, model, expectedMessage, model);
+ }
+
+ @Test
+ public void execute_invalidPersonIndexUnfilteredList_failure() {
+ Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
+ NoteCommand noteCommand = new NoteCommand(outOfBoundIndex, new Note(VALID_NOTE_BOB));
+
+ assertCommandFailure(noteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ /**
+ * Edit filtered list where index is larger than size of filtered list,
+ * but smaller than size of address book
+ */
+ @Test
+ public void execute_invalidPersonIndexFilteredList_failure() {
+ showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ Index outOfBoundIndex = INDEX_SECOND_PERSON;
+ // ensures that outOfBoundIndex is still in bounds of address book list
+ assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
+
+ NoteCommand remarkCommand = new NoteCommand(outOfBoundIndex, new Note(VALID_NOTE_BOB));
+
+ assertCommandFailure(remarkCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ @Test
+ public void equals() {
+ final NoteCommand standardCommand = new NoteCommand(INDEX_FIRST_PERSON,
+ new Note(VALID_NOTE_AMY));
+
+ // same values -> returns true
+ NoteCommand commandWithSameValues = new NoteCommand(INDEX_FIRST_PERSON,
+ new Note(VALID_NOTE_AMY));
+ assertTrue(standardCommand.equals(commandWithSameValues));
+
+ // same object -> returns true
+ assertTrue(standardCommand.equals(standardCommand));
+
+ // null -> returns false
+ assertFalse(standardCommand.equals(null));
+
+ // different types -> returns false
+ assertFalse(standardCommand.equals(new ClearCommand()));
+
+ // different index -> returns false
+ assertFalse(standardCommand.equals(new NoteCommand(INDEX_SECOND_PERSON,
+ new Note(VALID_NOTE_AMY))));
+
+ // different remark -> returns false
+ assertFalse(standardCommand.equals(new NoteCommand(INDEX_FIRST_PERSON,
+ new Note(VALID_NOTE_BOB))));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/ViewCommandTest.java b/src/test/java/seedu/address/logic/commands/ViewCommandTest.java
new file mode 100644
index 00000000000..d00f5985850
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/ViewCommandTest.java
@@ -0,0 +1,124 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.parser.ViewCommandParser;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.AddressBook;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.ProfileContainsKeywordsPredicate;
+import seedu.address.testutil.PersonBuilder;
+import seedu.address.testutil.TypicalPersons;
+
+public class ViewCommandTest {
+
+ private Model model;
+
+ private final ViewCommandParser parser = new ViewCommandParser();
+
+ @BeforeEach
+ public void setUp() {
+ AddressBook ab = new AddressBook();
+ ab.setPersons(TypicalPersons.getTypicalPersons());
+ Person davidLi = new PersonBuilder().withName("David Li").withNric("S0101010A").build();
+ ab.addPerson(davidLi);
+ model = new ModelManager(ab, new UserPrefs());
+ }
+
+ @Test
+ public void toStringMethod() {
+ ProfileContainsKeywordsPredicate predicate = new ProfileContainsKeywordsPredicate(Arrays.asList("keyword"));
+ ViewCommand findCommand = new ViewCommand(predicate);
+ String expected = ViewCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
+ assertEquals(expected, findCommand.toString());
+ }
+
+ @Test
+ public void equals() {
+ ProfileContainsKeywordsPredicate firstPredicate =
+ new ProfileContainsKeywordsPredicate(Collections.singletonList("first"));
+ ProfileContainsKeywordsPredicate secondPredicate =
+ new ProfileContainsKeywordsPredicate(Collections.singletonList("second"));
+
+ ViewCommand viewFirstCommand = new ViewCommand(firstPredicate);
+ ViewCommand viewSecondCommand = new ViewCommand(secondPredicate);
+
+ // same object -> returns true
+ assertTrue(viewFirstCommand.equals(viewFirstCommand));
+
+ // same values -> returns true
+ ViewCommand viewFirstCommandCopy = new ViewCommand(firstPredicate);
+ assertTrue(viewFirstCommand.equals(viewFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(viewFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(viewFirstCommand.equals(null));
+
+ // different predicate -> returns false
+ assertFalse(viewFirstCommand.equals(viewSecondCommand));
+ }
+
+ @Test
+ public void execute_viewFullName_success() {
+ // Prepare predicate and command
+ ProfileContainsKeywordsPredicate predicate = new ProfileContainsKeywordsPredicate(List.of("David Li"));
+ ViewCommand viewCommand = new ViewCommand(predicate);
+
+ // Update model expected state
+ model.updateFilteredPersonList(predicate);
+
+ // Execute command and assert result
+ CommandResult result = viewCommand.execute(model);
+ assertEquals("Profile found: David Li", result.getFeedbackToUser());
+ }
+
+ @Test
+ public void execute_viewSurname_success() {
+ ProfileContainsKeywordsPredicate predicate = new ProfileContainsKeywordsPredicate(List.of("David Li"));
+ ViewCommand viewCommand = new ViewCommand(predicate);
+ model.updateFilteredPersonList(predicate);
+
+ CommandResult result = viewCommand.execute(model);
+ assertEquals("Profile found: David Li", result.getFeedbackToUser());
+ }
+
+ @Test
+ public void execute_personNotFound_returnsNoMatch() {
+ // Non-matching keyword
+ ProfileContainsKeywordsPredicate predicate = new ProfileContainsKeywordsPredicate(List.of("Bob"));
+ ViewCommand viewCommand = new ViewCommand(predicate);
+
+ CommandResult result = viewCommand.execute(model);
+
+ String expectedMessage = String.format(
+ "%s",
+ "No matching profile found!!"
+ );
+
+ assertEquals(expectedMessage, result.getFeedbackToUser());
+ }
+
+ @Test
+ public void parse_invalidSymbols_throwsParseException() {
+ ParseException thrown = assertThrows(ParseException.class, () ->
+ parser.parse("@lex"));
+ assert(thrown.getMessage().equals("Names should only contain alphabetical characters and spaces."));
+ }
+}
+
+
diff --git a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
index 5bc11d3cdaa..e32b5fca20a 100644
--- a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
@@ -3,30 +3,53 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.DATE_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.DATE_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.DOB_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.DOB_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.GENDER_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.GENDER_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_DATE_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_DOB_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_GENDER_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_NATIONALITY_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_NRIC_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.NATIONALITY_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.NATIONALITY_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.NRIC_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.NRIC_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY;
import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_MARKETING;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DATE_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DOB_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GENDER_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NATIONALITY_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NRIC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_MARKETING;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DOB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GENDER;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NATIONALITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NRIC;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
@@ -38,11 +61,16 @@
import seedu.address.logic.Messages;
import seedu.address.logic.commands.AddCommand;
import seedu.address.model.person.Address;
+import seedu.address.model.person.DateOfJoining;
+import seedu.address.model.person.Dob;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Gender;
import seedu.address.model.person.Name;
+import seedu.address.model.person.Nationality;
+import seedu.address.model.person.Nric;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.tag.Department;
import seedu.address.testutil.PersonBuilder;
public class AddCommandParserTest {
@@ -50,25 +78,29 @@ public class AddCommandParserTest {
@Test
public void parse_allFieldsPresent_success() {
- Person expectedPerson = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND).build();
+ Person expectedPerson = new PersonBuilder(BOB).withTags(VALID_TAG_MARKETING).build();
// whitespace only preamble
assertParseSuccess(parser, PREAMBLE_WHITESPACE + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson));
+ + NRIC_DESC_BOB + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_MARKETING, new AddCommand(expectedPerson));
// multiple tags - all accepted
- Person expectedPersonMultipleTags = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND, VALID_TAG_HUSBAND)
+ Person expectedPersonMultipleTags = new PersonBuilder(BOB).withTags(VALID_TAG_MARKETING)
.build();
assertParseSuccess(parser,
- NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND,
+ NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB + GENDER_DESC_BOB
+ + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_MARKETING,
new AddCommand(expectedPersonMultipleTags));
}
@Test
public void parse_repeatedNonTagValue_failure() {
- String validExpectedPersonString = NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND;
+ String validExpectedPersonString = NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_MARKETING;
// multiple names
assertParseFailure(parser, NAME_DESC_AMY + validExpectedPersonString,
@@ -82,15 +114,38 @@ public void parse_repeatedNonTagValue_failure() {
assertParseFailure(parser, EMAIL_DESC_AMY + validExpectedPersonString,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_EMAIL));
+ // multiple nrics
+ assertParseFailure(parser, NRIC_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NRIC));
+
+ // multiple genders
+ assertParseFailure(parser, GENDER_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_GENDER));
+
+ // multiple nationalities
+ assertParseFailure(parser, NATIONALITY_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NATIONALITY));
+
+ // multiple dobs
+ assertParseFailure(parser, DOB_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_DOB));
+
+ // multiple dates of joining
+ assertParseFailure(parser, DATE_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_DATE));
+
// multiple addresses
assertParseFailure(parser, ADDRESS_DESC_AMY + validExpectedPersonString,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_ADDRESS));
// multiple fields repeated
assertParseFailure(parser,
- validExpectedPersonString + PHONE_DESC_AMY + EMAIL_DESC_AMY + NAME_DESC_AMY + ADDRESS_DESC_AMY
+ validExpectedPersonString + PHONE_DESC_AMY + EMAIL_DESC_AMY + NRIC_DESC_AMY
+ + GENDER_DESC_AMY + DOB_DESC_AMY + DATE_DESC_AMY + NATIONALITY_DESC_AMY
+ + NAME_DESC_AMY + ADDRESS_DESC_AMY
+ validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME, PREFIX_ADDRESS, PREFIX_EMAIL, PREFIX_PHONE));
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME, PREFIX_ADDRESS, PREFIX_NRIC,
+ PREFIX_GENDER, PREFIX_DOB, PREFIX_DATE, PREFIX_NATIONALITY, PREFIX_EMAIL, PREFIX_PHONE));
// invalid value followed by valid value
@@ -102,6 +157,26 @@ public void parse_repeatedNonTagValue_failure() {
assertParseFailure(parser, INVALID_EMAIL_DESC + validExpectedPersonString,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_EMAIL));
+ // invalid nric
+ assertParseFailure(parser, INVALID_NRIC_DESC + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NRIC));
+
+ // invalid gender
+ assertParseFailure(parser, INVALID_GENDER_DESC + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_GENDER));
+
+ // invalid dob
+ assertParseFailure(parser, INVALID_DOB_DESC + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_DOB));
+
+ // invalid date of joining
+ assertParseFailure(parser, INVALID_DATE_DESC + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_DATE));
+
+ // invalid nationality
+ assertParseFailure(parser, INVALID_NATIONALITY_DESC + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NATIONALITY));
+
// invalid phone
assertParseFailure(parser, INVALID_PHONE_DESC + validExpectedPersonString,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE));
@@ -120,6 +195,25 @@ public void parse_repeatedNonTagValue_failure() {
assertParseFailure(parser, validExpectedPersonString + INVALID_EMAIL_DESC,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_EMAIL));
+ // invalid nric
+ assertParseFailure(parser, validExpectedPersonString + INVALID_NRIC_DESC,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NRIC));
+
+ // invalid gender
+ assertParseFailure(parser, validExpectedPersonString + INVALID_GENDER_DESC,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_GENDER));
+
+ // invalid dob
+ assertParseFailure(parser, validExpectedPersonString + INVALID_DOB_DESC,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_DOB));
+
+ assertParseFailure(parser, validExpectedPersonString + INVALID_DATE_DESC,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_DATE));
+
+ // invalid nationality
+ assertParseFailure(parser, validExpectedPersonString + INVALID_NATIONALITY_DESC,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NATIONALITY));
+
// invalid phone
assertParseFailure(parser, validExpectedPersonString + INVALID_PHONE_DESC,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE));
@@ -132,65 +226,159 @@ public void parse_repeatedNonTagValue_failure() {
@Test
public void parse_optionalFieldsMissing_success() {
// zero tags
- Person expectedPerson = new PersonBuilder(AMY).withTags().build();
- assertParseSuccess(parser, NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY + ADDRESS_DESC_AMY,
+ Person expectedPerson = new PersonBuilder(AMY).withTags(VALID_TAG_MARKETING).build();
+ assertParseSuccess(parser, NAME_DESC_AMY + PHONE_DESC_AMY
+ + EMAIL_DESC_AMY + NRIC_DESC_AMY + GENDER_DESC_AMY + DOB_DESC_AMY
+ + DATE_DESC_AMY + NATIONALITY_DESC_AMY
+ + ADDRESS_DESC_AMY + TAG_DESC_MARKETING,
new AddCommand(expectedPerson));
}
@Test
public void parse_compulsoryFieldMissing_failure() {
- String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE);
-
// missing name prefix
- assertParseFailure(parser, VALID_NAME_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB,
- expectedMessage);
+ assertParseFailure(parser, VALID_NAME_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_MARKETING,
+ "Missing required field: name (n/)\n"
+ + "Eg: n/John Doe");
// missing phone prefix
- assertParseFailure(parser, NAME_DESC_BOB + VALID_PHONE_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB,
- expectedMessage);
+ assertParseFailure(parser, NAME_DESC_BOB + VALID_PHONE_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_MARKETING,
+ "Missing required field: phone (p/)\n"
+ + "Eg: p/91234567");
// missing email prefix
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + VALID_EMAIL_BOB + ADDRESS_DESC_BOB,
- expectedMessage);
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + VALID_EMAIL_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_MARKETING,
+ "Missing required field: email (e/)\n"
+ + "Eg: e/johndoe@example.com");
+
+ // missing nric prefix
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + VALID_NRIC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_MARKETING,
+ "Missing required field: NRIC (ic/)\n"
+ + "Eg: ic/S1234567D");
+
+ // missing gender prefix
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + VALID_GENDER_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_MARKETING,
+ "Missing required field: gender (g/)\n"
+ + "Eg: g/Male");
+
+ // missing dob prefix
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + VALID_DOB_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_MARKETING,
+ "Missing required field: date of birth (d/)\n"
+ + "Eg: d/20-03-1990");
+
+ // missing date of joining prefix
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + VALID_DATE_BOB + NATIONALITY_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_MARKETING,
+ "Missing required field: date of joining (j/)\n"
+ + "Eg: j/15-04-2023");
+
+ // missing nationality prefix
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + VALID_NATIONALITY_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_MARKETING,
+ "Missing required field: nationality (nat/)\n"
+ + "Eg: nat/Singaporean");
// missing address prefix
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + VALID_ADDRESS_BOB,
- expectedMessage);
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB
+ + VALID_ADDRESS_BOB + TAG_DESC_MARKETING,
+ "Missing required field: address (a/)\n"
+ + "Eg: a/123 Main Street #05-01/119278");
+
+ // missing tag prefix
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB
+ + ADDRESS_DESC_BOB,
+ "Missing required field: tag (t/)\n"
+ + "Eg: t/Marketing/Full-Time/Product Manager");
// all prefixes missing
- assertParseFailure(parser, VALID_NAME_BOB + VALID_PHONE_BOB + VALID_EMAIL_BOB + VALID_ADDRESS_BOB,
- expectedMessage);
+ assertParseFailure(parser, VALID_NAME_BOB + VALID_PHONE_BOB + VALID_EMAIL_BOB + VALID_NRIC_BOB
+ + VALID_GENDER_BOB + VALID_DOB_BOB + VALID_DATE_BOB + VALID_NATIONALITY_BOB
+ + VALID_ADDRESS_BOB,
+ "Missing required field: name (n/) phone (p/) email (e/) NRIC (ic/) gender (g/) "
+ + "date of birth (d/) date of joining (j/) nationality (nat/) address (a/) tag (t/)\n"
+ + "Eg: n/John Doe p/91234567 e/johndoe@example.com ic/S1234567D g/Male "
+ + "d/20-03-1990 j/15-04-2023 nat/Singaporean a/123 Main Street #05-01/119278 "
+ + "t/Marketing/Full-Time/Product Manager");
}
@Test
public void parse_invalidValue_failure() {
// invalid name
- assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Name.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_MARKETING, Name.MESSAGE_CONSTRAINTS);
// invalid phone
- assertParseFailure(parser, NAME_DESC_BOB + INVALID_PHONE_DESC + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Phone.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, NAME_DESC_BOB + INVALID_PHONE_DESC + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_MARKETING, Phone.MESSAGE_CONSTRAINTS);
// invalid email
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + INVALID_EMAIL_DESC + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Email.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + INVALID_EMAIL_DESC + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_MARKETING, Email.MESSAGE_CONSTRAINTS);
+
+ // invalid nric
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_NRIC_DESC
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_MARKETING, Nric.MESSAGE_CONSTRAINTS);
+
+ // invalid gender
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + INVALID_GENDER_DESC + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_MARKETING, Gender.MESSAGE_CONSTRAINTS);
+
+ // invalid dob
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + INVALID_DOB_DESC + DATE_DESC_BOB + NATIONALITY_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_MARKETING, Dob.MESSAGE_CONSTRAINTS);
+
+ // invalid dateOfJoining
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + INVALID_DATE_DESC + NATIONALITY_DESC_BOB + ADDRESS_DESC_BOB
+ + TAG_DESC_MARKETING, DateOfJoining.MESSAGE_CONSTRAINTS);
+
+ // invalid nationality
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + INVALID_NATIONALITY_DESC + ADDRESS_DESC_BOB
+ + TAG_DESC_MARKETING, Nationality.MESSAGE_CONSTRAINTS);
// invalid address
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Address.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB + INVALID_ADDRESS_DESC
+ + TAG_DESC_MARKETING, Address.MESSAGE_CONSTRAINTS);
// invalid tag
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + INVALID_TAG_DESC + VALID_TAG_FRIEND, Tag.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB + ADDRESS_DESC_BOB
+ + INVALID_TAG_DESC, Department.MESSAGE_CONSTRAINTS);
// two invalid values, only first invalid value reported
- assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC,
+ assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + NRIC_DESC_BOB
+ + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB + INVALID_ADDRESS_DESC
+ + TAG_DESC_MARKETING,
Name.MESSAGE_CONSTRAINTS);
// non-empty preamble
assertParseFailure(parser, PREAMBLE_NON_EMPTY + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND,
+ + NRIC_DESC_BOB + GENDER_DESC_BOB + DOB_DESC_BOB + DATE_DESC_BOB + NATIONALITY_DESC_BOB
+ + ADDRESS_DESC_BOB + TAG_DESC_MARKETING,
String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
}
}
diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
index 5a1ab3dbc0c..f286a1f7fed 100644
--- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
@@ -9,22 +9,24 @@
import java.util.Arrays;
import java.util.List;
-import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
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.EditCommand.EditPersonDescriptor;
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.commands.NoteCommand;
+import seedu.address.logic.commands.ViewCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.Note;
import seedu.address.model.person.Person;
+import seedu.address.model.person.ProfileContainsKeywordsPredicate;
import seedu.address.testutil.EditPersonDescriptorBuilder;
import seedu.address.testutil.PersonBuilder;
import seedu.address.testutil.PersonUtil;
@@ -53,15 +55,26 @@ public void parseCommand_delete() throws Exception {
assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), command);
}
+ @Test
+ public void parseCommand_view() throws Exception {
+ List inputNames = Arrays.asList("David Li");
+ String input = ViewCommand.COMMAND_WORD + " " + String.join(" ", inputNames);
+ ViewCommand expectedCommand = new ViewCommand(new ProfileContainsKeywordsPredicate(inputNames));
+
+ Command parsedCommand = parser.parseCommand(input);
+ assertEquals(expectedCommand, parsedCommand);
+ }
+
@Test
public void parseCommand_edit() throws Exception {
Person person = new PersonBuilder().build();
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(person).build();
+ EditCommand.EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(person).build();
EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " "
+ INDEX_FIRST_PERSON.getOneBased() + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor));
assertEquals(new EditCommand(INDEX_FIRST_PERSON, descriptor), command);
}
+
@Test
public void parseCommand_exit() throws Exception {
assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD) instanceof ExitCommand);
@@ -70,10 +83,10 @@ public void parseCommand_exit() throws Exception {
@Test
public void parseCommand_find() throws Exception {
- List keywords = Arrays.asList("foo", "bar", "baz");
- FindCommand command = (FindCommand) parser.parseCommand(
- FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" ")));
- assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command);
+ // Simulate the user typing the 'find' command, which is invalid now
+ assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindCommand.MESSAGE_USAGE), () ->
+ parser.parseCommand(FindCommand.COMMAND_WORD + " foo bar"));
}
@Test
@@ -88,6 +101,14 @@ public void parseCommand_list() throws Exception {
assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand);
}
+ @Test
+ public void parseCommand_note() throws Exception {
+ final Note note = new Note("Some remark.");
+ NoteCommand command = (NoteCommand) parser.parseCommand(NoteCommand.COMMAND_WORD + " "
+ + INDEX_FIRST_PERSON.getOneBased() + " " + note.value);
+ assertEquals(new NoteCommand(INDEX_FIRST_PERSON, note), command);
+ }
+
@Test
public void parseCommand_unrecognisedInput_throwsParseException() {
assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), ()
@@ -99,3 +120,4 @@ public void parseCommand_unknownCommand_throwsParseException() {
assertThrows(ParseException.class, MESSAGE_UNKNOWN_COMMAND, () -> parser.parseCommand("unknownCommand"));
}
}
+
diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
index cc7175172d4..d6ab49ca1bf 100644
--- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
@@ -1,27 +1,36 @@
package seedu.address.logic.parser;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.DATE_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.DOB_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.GENDER_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.NATIONALITY_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUMAN_RESOURCE;
+import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_MARKETING;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DATE_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DOB_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GENDER_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NATIONALITY_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUMAN_RESOURCE;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_MARKETING;
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_PHONE;
@@ -42,6 +51,7 @@
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
+import seedu.address.model.tag.Department;
import seedu.address.model.tag.Tag;
import seedu.address.testutil.EditPersonDescriptorBuilder;
@@ -59,9 +69,6 @@ public void parse_missingParts_failure() {
// no index specified
assertParseFailure(parser, VALID_NAME_AMY, MESSAGE_INVALID_FORMAT);
- // no field specified
- assertParseFailure(parser, "1", EditCommand.MESSAGE_NOT_EDITED);
-
// no index and no field specified
assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT);
}
@@ -69,10 +76,10 @@ public void parse_missingParts_failure() {
@Test
public void parse_invalidPreamble_failure() {
// negative index
- assertParseFailure(parser, "-5" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, "-5" + NAME_DESC_AMY, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
// zero index
- assertParseFailure(parser, "0" + NAME_DESC_AMY, MESSAGE_INVALID_FORMAT);
+ assertParseFailure(parser, "0" + NAME_DESC_AMY, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
// invalid arguments being parsed as preamble
assertParseFailure(parser, "1 some random string", MESSAGE_INVALID_FORMAT);
@@ -87,16 +94,14 @@ public void parse_invalidValue_failure() {
assertParseFailure(parser, "1" + INVALID_PHONE_DESC, Phone.MESSAGE_CONSTRAINTS); // invalid phone
assertParseFailure(parser, "1" + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email
assertParseFailure(parser, "1" + INVALID_ADDRESS_DESC, Address.MESSAGE_CONSTRAINTS); // invalid address
- assertParseFailure(parser, "1" + INVALID_TAG_DESC, Tag.MESSAGE_CONSTRAINTS); // invalid tag
+ assertParseFailure(parser, "1" + INVALID_TAG_DESC, Department.MESSAGE_CONSTRAINTS); // invalid tag
// invalid phone followed by valid email
assertParseFailure(parser, "1" + INVALID_PHONE_DESC + EMAIL_DESC_AMY, Phone.MESSAGE_CONSTRAINTS);
// while parsing {@code PREFIX_TAG} alone will reset the tags of the {@code Person} being edited,
// parsing it together with a valid tag results in error
- assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_DESC_HUSBAND + TAG_EMPTY, Tag.MESSAGE_CONSTRAINTS);
- assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_EMPTY + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
- assertParseFailure(parser, "1" + TAG_EMPTY + TAG_DESC_FRIEND + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, "1" + TAG_EMPTY, Tag.MESSAGE_CONSTRAINTS);
// multiple invalid values, but only the first invalid value is captured
assertParseFailure(parser, "1" + INVALID_NAME_DESC + INVALID_EMAIL_DESC + VALID_ADDRESS_AMY + VALID_PHONE_AMY,
@@ -106,12 +111,15 @@ public void parse_invalidValue_failure() {
@Test
public void parse_allFieldsSpecified_success() {
Index targetIndex = INDEX_SECOND_PERSON;
- String userInput = targetIndex.getOneBased() + PHONE_DESC_BOB + TAG_DESC_HUSBAND
- + EMAIL_DESC_AMY + ADDRESS_DESC_AMY + NAME_DESC_AMY + TAG_DESC_FRIEND;
+ String userInput = targetIndex.getOneBased() + PHONE_DESC_BOB + EMAIL_DESC_AMY
+ + ADDRESS_DESC_AMY + NAME_DESC_AMY + TAG_DESC_HUMAN_RESOURCE
+ + GENDER_DESC_AMY + DOB_DESC_AMY + DATE_DESC_AMY + NATIONALITY_DESC_AMY;
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
- .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY)
- .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
+ .withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_AMY)
+ .withGender(VALID_GENDER_AMY).withDob(VALID_DOB_AMY).withDateOfJoining(VALID_DATE_AMY)
+ .withNationality(VALID_NATIONALITY_AMY).withAddress(VALID_ADDRESS_AMY)
+ .withTags(VALID_TAG_HUMAN_RESOURCE).build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
@@ -157,8 +165,8 @@ public void parse_oneFieldSpecified_success() {
assertParseSuccess(parser, userInput, expectedCommand);
// tags
- userInput = targetIndex.getOneBased() + TAG_DESC_FRIEND;
- descriptor = new EditPersonDescriptorBuilder().withTags(VALID_TAG_FRIEND).build();
+ userInput = targetIndex.getOneBased() + TAG_DESC_MARKETING;
+ descriptor = new EditPersonDescriptorBuilder().withTags(VALID_TAG_MARKETING).build();
expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
}
@@ -181,8 +189,8 @@ public void parse_multipleRepeatedFields_failure() {
// mulltiple valid fields repeated
userInput = targetIndex.getOneBased() + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY
- + TAG_DESC_FRIEND + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY + TAG_DESC_FRIEND
- + PHONE_DESC_BOB + ADDRESS_DESC_BOB + EMAIL_DESC_BOB + TAG_DESC_HUSBAND;
+ + TAG_DESC_MARKETING + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY
+ + PHONE_DESC_BOB + ADDRESS_DESC_BOB + EMAIL_DESC_BOB;
assertParseFailure(parser, userInput,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS));
@@ -198,9 +206,9 @@ public void parse_multipleRepeatedFields_failure() {
@Test
public void parse_resetTags_success() {
Index targetIndex = INDEX_THIRD_PERSON;
- String userInput = targetIndex.getOneBased() + TAG_EMPTY;
+ String userInput = targetIndex.getOneBased() + TAG_DESC_HUMAN_RESOURCE;
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withTags().build();
+ EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withTags(VALID_TAG_HUMAN_RESOURCE).build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
diff --git a/src/test/java/seedu/address/logic/parser/FindByDepartmentCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindByDepartmentCommandParserTest.java
new file mode 100644
index 00000000000..863d7e2e484
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FindByDepartmentCommandParserTest.java
@@ -0,0 +1,34 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.FindByDepartmentCommand;
+import seedu.address.model.person.DepartmentContainsKeywordPredicate;
+import seedu.address.model.tag.Department;
+
+public class FindByDepartmentCommandParserTest {
+
+ private FindByDepartmentCommandParser parser = new FindByDepartmentCommandParser();
+
+ @Test
+ public void parse_invalidDepartmentWithNumbers_throwsParseException() {
+ assertParseFailure(parser, "HR123", "Department does not exist. "
+ + Department.MESSAGE_CONSTRAINTS);
+ }
+
+ @Test
+ public void parse_invalidDepartmentWithSpecialChars_throwsParseException() {
+ assertParseFailure(parser, "Finance#", "Department does not exist. "
+ + Department.MESSAGE_CONSTRAINTS);
+ }
+
+ @Test
+ public void parse_validDepartmentWithAmpersand_returnsFindByDepartmentCommand() {
+ FindByDepartmentCommand expectedCommand =
+ new FindByDepartmentCommand(new DepartmentContainsKeywordPredicate("R&D"));
+ assertParseSuccess(parser, "R&D", expectedCommand);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/FindByEmploymentTypeCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindByEmploymentTypeCommandParserTest.java
new file mode 100644
index 00000000000..32453bbe2ee
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FindByEmploymentTypeCommandParserTest.java
@@ -0,0 +1,44 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.FindByEmploymentTypeCommand;
+import seedu.address.model.person.EmploymentTypeContainsKeywordPredicate;
+
+public class FindByEmploymentTypeCommandParserTest {
+
+ private FindByEmploymentTypeCommandParser parser = new FindByEmploymentTypeCommandParser();
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindByEmploymentTypeCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsFindByEmploymentTypeCommand() {
+ // no leading and trailing whitespaces
+ FindByEmploymentTypeCommand expectedFindByEmploymentTypeCommand =
+ new FindByEmploymentTypeCommand(new EmploymentTypeContainsKeywordPredicate("Full-time"));
+ assertParseSuccess(parser, "Full-time", expectedFindByEmploymentTypeCommand);
+
+ // multiple whitespaces between keywords
+ assertParseSuccess(parser, " \n Full-time \t", expectedFindByEmploymentTypeCommand);
+ }
+
+ @Test
+ public void parse_invalidEmploymentTypeWithNumbers_throwsParseException() {
+ assertParseFailure(parser, "Full-time123",
+ FindByEmploymentTypeCommandParser.MESSAGE_EMPLOYMENTTYPE_CONSTRAINTS);
+ }
+
+ @Test
+ public void parse_invalidEmploymentTypeWithSpecialChars_throwsParseException() {
+ assertParseFailure(parser, "Part-time@",
+ FindByEmploymentTypeCommandParser.MESSAGE_EMPLOYMENTTYPE_CONSTRAINTS);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/FindByJobTitleCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindByJobTitleCommandParserTest.java
new file mode 100644
index 00000000000..25c4d170349
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FindByJobTitleCommandParserTest.java
@@ -0,0 +1,46 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.FindByJobTitleCommand;
+import seedu.address.model.person.JobTitleContainsKeywordPredicate;
+
+public class FindByJobTitleCommandParserTest {
+
+ private FindByJobTitleCommandParser parser = new FindByJobTitleCommandParser();
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindByJobTitleCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsFindByJobTitleCommand() {
+ // no leading and trailing whitespaces
+ FindByJobTitleCommand expectedFindByJobTitleCommand =
+ new FindByJobTitleCommand(new JobTitleContainsKeywordPredicate("Engineer"));
+ assertParseSuccess(parser, "Engineer", expectedFindByJobTitleCommand);
+
+ // multiple whitespaces between keywords
+ assertParseSuccess(parser, " \n Engineer \t", expectedFindByJobTitleCommand);
+ }
+
+ @Test
+ public void parse_invalidJobTitleWithNumbers_throwsParseException() {
+ assertParseFailure(parser, "Engineer123",
+ FindByJobTitleCommand.MESSAGE_JOBTITLE_CONSTRAINTS);
+ }
+
+ @Test
+ public void parse_invalidJobTitleWithSpecialChars_throwsParseException() {
+ assertParseFailure(parser, "Manager@",
+ FindByJobTitleCommand.MESSAGE_JOBTITLE_CONSTRAINTS);
+ }
+}
+
+
diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
index d92e64d12f9..9d0ee469c31 100644
--- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
@@ -1,34 +1,29 @@
package seedu.address.logic.parser;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-
-import java.util.Arrays;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.logic.parser.exceptions.ParseException;
public class FindCommandParserTest {
- private FindCommandParser parser = new FindCommandParser();
+ private final FindCommandParser parser = new FindCommandParser();
@Test
public void parse_emptyArg_throwsParseException() {
- assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ // Expect a ParseException when no arguments are provided
+ assertThrows(ParseException.class, () -> parser.parse("find"));
}
@Test
- public void parse_validArgs_returnsFindCommand() {
- // no leading and trailing whitespaces
- FindCommand expectedFindCommand =
- new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
- assertParseSuccess(parser, "Alice Bob", expectedFindCommand);
-
- // multiple whitespaces between keywords
- assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFindCommand);
+ public void parse_validArgs_throwsParseException() {
+ // Expect a ParseException when arguments are passed with the "find" command
+ assertThrows(ParseException.class, () -> parser.parse("find foo bar"));
}
-}
+ @Test
+ public void parse_noArguments_throwsParseException() {
+ assertThrows(ParseException.class, () -> parser.parse("find"));
+ }
+};
diff --git a/src/test/java/seedu/address/logic/parser/NoteCommandParserTest.java b/src/test/java/seedu/address/logic/parser/NoteCommandParserTest.java
new file mode 100644
index 00000000000..1af96f2cccc
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/NoteCommandParserTest.java
@@ -0,0 +1,42 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.NoteCommand;
+import seedu.address.model.person.Note;
+
+public class NoteCommandParserTest {
+ private NoteCommandParser parser = new NoteCommandParser();
+ private final String nonEmptyRemark = "Some remark.";
+
+ @Test
+ public void parse_indexSpecified_success() {
+ // have remark
+ Index targetIndex = INDEX_FIRST_PERSON;
+ String userInput = targetIndex.getOneBased() + " " + nonEmptyRemark;
+ NoteCommand expectedCommand = new NoteCommand(INDEX_FIRST_PERSON, new Note(nonEmptyRemark));
+ assertParseSuccess(parser, userInput, expectedCommand);
+
+ // no remark
+ userInput = targetIndex.getOneBased() + " ";
+ expectedCommand = new NoteCommand(INDEX_FIRST_PERSON, new Note(" "));
+ assertParseSuccess(parser, userInput, expectedCommand);
+ }
+
+ @Test
+ public void parse_missingCompulsoryField_failure() {
+ String expectedMessage = String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, NoteCommand.MESSAGE_USAGE);
+
+ // no parameters
+ assertParseFailure(parser, NoteCommand.COMMAND_WORD, expectedMessage);
+
+ // no index
+ assertParseFailure(parser, NoteCommand.COMMAND_WORD + " " + nonEmptyRemark, expectedMessage);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
index 4256788b1a7..d210c029214 100644
--- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
+++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
@@ -1,23 +1,22 @@
package seedu.address.logic.parser;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.parser.ParserUtil.MESSAGE_INVALID_INDEX;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
import org.junit.jupiter.api.Test;
+import seedu.address.logic.commands.FindCommand;
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.Department;
+import seedu.address.model.tag.EmploymentType;
+import seedu.address.model.tag.JobTitle;
import seedu.address.model.tag.Tag;
public class ParserUtilTest {
@@ -25,35 +24,49 @@ public class ParserUtilTest {
private static final String INVALID_PHONE = "+651234";
private static final String INVALID_ADDRESS = " ";
private static final String INVALID_EMAIL = "example.com";
- private static final String INVALID_TAG = "#friend";
+ private static final String INVALID_TAG = "#Human Resource/Full-Time/HR Coordinator";
private static final String VALID_NAME = "Rachel Walker";
- private static final String VALID_PHONE = "123456";
- private static final String VALID_ADDRESS = "123 Main Street #0505";
+ private static final String VALID_PHONE = "83075829";
+ private static final String VALID_ADDRESS = "123 Main Street #0505/233948";
private static final String VALID_EMAIL = "rachel@example.com";
- private static final String VALID_TAG_1 = "friend";
- private static final String VALID_TAG_2 = "neighbour";
-
+ private static final String VALID_DEPARTMENT_1 = "Human Resources";
+ private static final String VALID_EMPLOYMENT_TYPE_1 = "Full-Time";
+ private static final String VALID_JOB_TITLE_1 = "HR Coordinator";
private static final String WHITESPACE = " \t\r\n";
+ private final AddressBookParser parser = new AddressBookParser();
+ @Test
+ public void parseFindCommand_invalidCommand_throwsParseException() {
+ assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindCommand.MESSAGE_USAGE), () ->
+ parser.parseCommand("find foo bar"));
+ }
+
@Test
public void parseIndex_invalidInput_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parseIndex("10 a"));
+ assertThrows(ParseException.class, () -> ParserUtil.parseIndex("10 a", "Test Command Usage"));
}
@Test
public void parseIndex_outOfRangeInput_throwsParseException() {
- assertThrows(ParseException.class, MESSAGE_INVALID_INDEX, ()
- -> ParserUtil.parseIndex(Long.toString(Integer.MAX_VALUE + 1)));
+ assertThrows(ParseException.class, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX, ()
+ -> ParserUtil.parseIndex(Long.toString(Integer.MAX_VALUE + 1), "Test Command Usage"));
+
+ assertThrows(ParseException.class, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX, ()
+ -> ParserUtil.parseIndex(Long.toString((long) Integer.MAX_VALUE + 1), "Test Command Usage"));
+
+ assertThrows(ParseException.class, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX, ()
+ -> ParserUtil.parseIndex(Long.toString((long) Integer.MIN_VALUE - 1), "Test Command Usage"));
}
@Test
public void parseIndex_validInput_success() throws Exception {
// No whitespaces
- assertEquals(INDEX_FIRST_PERSON, ParserUtil.parseIndex("1"));
+ assertEquals(INDEX_FIRST_PERSON, ParserUtil.parseIndex("1", "Test Command Usage"));
// Leading and trailing whitespaces
- assertEquals(INDEX_FIRST_PERSON, ParserUtil.parseIndex(" 1 "));
+ assertEquals(INDEX_FIRST_PERSON, ParserUtil.parseIndex(" 1 ", "Test Command Usage"));
}
@Test
@@ -160,37 +173,66 @@ public void parseTag_invalidValue_throwsParseException() {
@Test
public void parseTag_validValueWithoutWhitespace_returnsTag() throws Exception {
- Tag expectedTag = new Tag(VALID_TAG_1);
- assertEquals(expectedTag, ParserUtil.parseTag(VALID_TAG_1));
+ Department department = new Department(VALID_DEPARTMENT_1);
+ EmploymentType employmentType = new EmploymentType(VALID_EMPLOYMENT_TYPE_1);
+ JobTitle jobTitle = new JobTitle(VALID_JOB_TITLE_1);
+ Tag expectedTag = new Tag(department, employmentType, jobTitle);
+ assertEquals(expectedTag, ParserUtil.parseTag("Human Resources/Full-Time/HR Coordinator"));
+ }
+
+ @Test
+ public void parseDepartment_validValueWithWhitespace_returnsTrimmedTag() throws Exception {
+ String departmentWithWhitespace = WHITESPACE + VALID_DEPARTMENT_1 + WHITESPACE;
+ Department department = new Department(departmentWithWhitespace);
+ EmploymentType employmentType = new EmploymentType(VALID_EMPLOYMENT_TYPE_1);
+ JobTitle jobTitle = new JobTitle(VALID_JOB_TITLE_1);
+ Tag expectedTag = new Tag(department, employmentType, jobTitle);
+ assertEquals(expectedTag, ParserUtil.parseTag("Human Resources/Full-Time/HR Coordinator"));
}
@Test
- public void parseTag_validValueWithWhitespace_returnsTrimmedTag() throws Exception {
- String tagWithWhitespace = WHITESPACE + VALID_TAG_1 + WHITESPACE;
- Tag expectedTag = new Tag(VALID_TAG_1);
- assertEquals(expectedTag, ParserUtil.parseTag(tagWithWhitespace));
+ public void parseEmploymentType_validValueWithWhitespace_returnsTrimmedTag() throws Exception {
+ String employmentWithWhiteSpace = WHITESPACE + VALID_EMPLOYMENT_TYPE_1 + WHITESPACE;
+ Department department = new Department(VALID_DEPARTMENT_1);
+ EmploymentType employmentType = new EmploymentType(employmentWithWhiteSpace);
+ JobTitle jobTitle = new JobTitle(VALID_JOB_TITLE_1);
+ Tag expectedTag = new Tag(department, employmentType, jobTitle);
+ assertEquals(expectedTag, ParserUtil.parseTag("Human Resources/Full-Time/HR Coordinator"));
}
@Test
- public void parseTags_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> ParserUtil.parseTags(null));
+ public void parseJobTitle_validValueWithWhitespace_returnsTrimmedTag() throws Exception {
+ String jobWithWhiteSpace = WHITESPACE + VALID_JOB_TITLE_1 + WHITESPACE;
+ Department department = new Department(VALID_DEPARTMENT_1);
+ EmploymentType employmentType = new EmploymentType(VALID_EMPLOYMENT_TYPE_1);
+ JobTitle jobTitle = new JobTitle(jobWithWhiteSpace);
+ Tag expectedTag = new Tag(department, employmentType, jobTitle);
+ assertEquals(expectedTag, ParserUtil.parseTag("Human Resources/Full-Time/HR Coordinator"));
}
@Test
public void parseTags_collectionWithInvalidTags_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, INVALID_TAG)));
+ assertThrows(ParseException.class, () -> ParserUtil.parseTag(INVALID_TAG));
}
@Test
public void parseTags_emptyCollection_returnsEmptySet() throws Exception {
- assertTrue(ParserUtil.parseTags(Collections.emptyList()).isEmpty());
+ Department department = new Department(VALID_DEPARTMENT_1);
+ EmploymentType employmentType = new EmploymentType(VALID_EMPLOYMENT_TYPE_1);
+ JobTitle jobTitle = new JobTitle(VALID_JOB_TITLE_1);
+ Tag expectedTag = new Tag(department, employmentType, jobTitle);
+ assertEquals(expectedTag, ParserUtil.parseTag("Human Resources/Full-Time/HR Coordinator"));
}
@Test
public void parseTags_collectionWithValidTags_returnsTagSet() throws Exception {
- Set actualTagSet = ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, VALID_TAG_2));
- Set expectedTagSet = new HashSet(Arrays.asList(new Tag(VALID_TAG_1), new Tag(VALID_TAG_2)));
+ Tag actualTag = ParserUtil.parseTag("Human Resources/Full-Time/HR Coordinator");
+
+ Department department = new Department(VALID_DEPARTMENT_1);
+ EmploymentType employmentType = new EmploymentType(VALID_EMPLOYMENT_TYPE_1);
+ JobTitle jobTitle = new JobTitle(VALID_JOB_TITLE_1);
+ Tag expectedTag = new Tag(department, employmentType, jobTitle);
- assertEquals(expectedTagSet, actualTagSet);
+ assertEquals(expectedTag, actualTag);
}
}
diff --git a/src/test/java/seedu/address/model/AddressBookTest.java b/src/test/java/seedu/address/model/AddressBookTest.java
index 68c8c5ba4d5..82946a16c9c 100644
--- a/src/test/java/seedu/address/model/AddressBookTest.java
+++ b/src/test/java/seedu/address/model/AddressBookTest.java
@@ -4,7 +4,7 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_MARKETING;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.ALICE;
import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
@@ -46,7 +46,7 @@ public void resetData_withValidReadOnlyAddressBook_replacesData() {
@Test
public void resetData_withDuplicatePersons_throwsDuplicatePersonException() {
// Two persons with the same identity fields
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
+ Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_MARKETING)
.build();
List newPersons = Arrays.asList(ALICE, editedAlice);
AddressBookStub newData = new AddressBookStub(newPersons);
@@ -73,7 +73,7 @@ public void hasPerson_personInAddressBook_returnsTrue() {
@Test
public void hasPerson_personWithSameIdentityFieldsInAddressBook_returnsTrue() {
addressBook.addPerson(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
+ Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_MARKETING)
.build();
assertTrue(addressBook.hasPerson(editedAlice));
}
diff --git a/src/test/java/seedu/address/model/person/AddressTest.java b/src/test/java/seedu/address/model/person/AddressTest.java
index 314885eca26..278809fcf35 100644
--- a/src/test/java/seedu/address/model/person/AddressTest.java
+++ b/src/test/java/seedu/address/model/person/AddressTest.java
@@ -29,17 +29,18 @@ public void isValidAddress() {
assertFalse(Address.isValidAddress(" ")); // spaces only
// valid addresses
- assertTrue(Address.isValidAddress("Blk 456, Den Road, #01-355"));
- assertTrue(Address.isValidAddress("-")); // one character
- assertTrue(Address.isValidAddress("Leng Inc; 1234 Market St; San Francisco CA 2349879; USA")); // long address
+ assertTrue(Address.isValidAddress("Blk 456, Den Road, #01-355/123456")); // alphanumeric characters
+ assertTrue(Address.isValidAddress("-/208290")); // one character
+ assertTrue(Address.isValidAddress("Leng Inc; 1234 Market St; San Francisco CA 2349879;"
+ + "USA/237891")); // long address
}
@Test
public void equals() {
- Address address = new Address("Valid Address");
+ Address address = new Address("Valid Address/098920");
// same values -> returns true
- assertTrue(address.equals(new Address("Valid Address")));
+ assertTrue(address.equals(new Address("Valid Address/098920")));
// same object -> returns true
assertTrue(address.equals(address));
@@ -51,6 +52,6 @@ public void equals() {
assertFalse(address.equals(5.0f));
// different values -> returns false
- assertFalse(address.equals(new Address("Other Valid Address")));
+ assertFalse(address.equals(new Address("Other Valid Address/238901")));
}
}
diff --git a/src/test/java/seedu/address/model/person/DateOfJoiningTest.java b/src/test/java/seedu/address/model/person/DateOfJoiningTest.java
new file mode 100644
index 00000000000..5156e5e1b28
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/DateOfJoiningTest.java
@@ -0,0 +1,60 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class DateOfJoiningTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new DateOfJoining(null));
+ }
+
+ @Test
+ public void constructor_invalidDateOfJoining_throwsIllegalArgumentException() {
+ String invalidDateOfJoining = "";
+ assertThrows(IllegalArgumentException.class, () -> new DateOfJoining(invalidDateOfJoining));
+ }
+
+ @Test
+ public void isValidDateOfJoining() {
+ assertThrows(NullPointerException.class, () -> DateOfJoining.isValidDate(null));
+
+ // invalid dates
+ assertFalse(DateOfJoining.isValidDate("")); // empty string
+ assertFalse(DateOfJoining.isValidDate(" ")); // spaces only
+ assertFalse(DateOfJoining.isValidDate("2025-may-01")); // wrong format
+ assertFalse(DateOfJoining.isValidDate("01 may 2025")); // wrong format
+ assertFalse(DateOfJoining.isValidDate("2025.01-01")); // wrong format
+
+ // valid dates
+ assertTrue(DateOfJoining.isValidDate("20-May-2025"));
+ assertTrue(DateOfJoining.isValidDate("2015-01-01"));
+ assertTrue(DateOfJoining.isValidDate("01-01-2025"));
+ assertTrue(DateOfJoining.isValidDate("01/01/2025"));
+ assertTrue(DateOfJoining.isValidDate("01.01.2025"));
+ }
+
+ @Test
+ public void equals() {
+ DateOfJoining date = new DateOfJoining("20-May-2023");
+
+ // same values -> returns true
+ assertTrue(date.equals(new DateOfJoining("20-May-2023")));
+
+ // same object -> returns true
+ assertTrue(date.equals(date));
+
+ // null -> returns false
+ assertFalse(date.equals(null));
+
+ // different types -> returns false
+ assertFalse(date.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(date.equals(new DateOfJoining("21-May-2023")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/DobTest.java b/src/test/java/seedu/address/model/person/DobTest.java
new file mode 100644
index 00000000000..fec5e802a1d
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/DobTest.java
@@ -0,0 +1,62 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class DobTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Dob(null));
+ }
+
+ @Test
+ public void constructor_invalidDob_throwsIllegalArgumentException() {
+ String invaliddob = "";
+ assertThrows(IllegalArgumentException.class, () -> new Dob(invaliddob));
+ }
+
+ @Test
+ public void isValidDob() {
+ assertThrows(NullPointerException.class, () -> Dob.isValidDob(null));
+
+ // invalid dates
+ assertFalse(Dob.isValidDob("")); // empty string
+ assertFalse(Dob.isValidDob(" ")); // spaces only
+ assertFalse(Dob.isValidDob("2025-may-01")); // wrong format
+ assertFalse(Dob.isValidDob("01 may 2025")); // wrong format
+ assertFalse(Dob.isValidDob("2025-may-90"));
+ assertFalse(Dob.isValidDate("32-Apr-2024"));
+
+ // valid dates
+ assertTrue(Dob.isValidDob("20-May-2025")); // correct format
+ assertTrue(Dob.isValidDob("2015-01-01")); // correct format
+ assertTrue(Dob.isValidDob("01-01-2025")); // correct format
+ assertTrue(Dob.isValidDob("01/01/2025"));
+ assertTrue(Dob.isValidDob("01.01.2025"));
+ assertTrue(Dob.isValidDate("30-Apr-2024"));
+ }
+
+ @Test
+ public void equals() {
+ Dob dob = new Dob("20-May-2023");
+
+ // same values -> returns true
+ assertTrue(dob.equals(new Dob("20-May-2023")));
+
+ // same object -> returns true
+ assertTrue(dob.equals(dob));
+
+ // null -> returns false
+ assertFalse(dob.equals(null));
+
+ // different types -> returns false
+ assertFalse(dob.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(dob.equals(new Dob("21-May-2023")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/EmailTest.java b/src/test/java/seedu/address/model/person/EmailTest.java
index f08cdff0a64..b93855da9ac 100644
--- a/src/test/java/seedu/address/model/person/EmailTest.java
+++ b/src/test/java/seedu/address/model/person/EmailTest.java
@@ -57,9 +57,9 @@ public void isValidEmail() {
assertTrue(Email.isValidEmail("PeterJack.1190@example.com")); // period in local part
assertTrue(Email.isValidEmail("PeterJack+1190@example.com")); // '+' symbol in local part
assertTrue(Email.isValidEmail("PeterJack-1190@example.com")); // hyphen in local part
- assertTrue(Email.isValidEmail("a@bc")); // minimal
- assertTrue(Email.isValidEmail("test@localhost")); // alphabets only
- assertTrue(Email.isValidEmail("123@145")); // numeric local part and domain name
+ assertTrue(Email.isValidEmail("a@b.com")); // minimal
+ assertTrue(Email.isValidEmail("test@localhost.com")); // alphabets only
+ assertTrue(Email.isValidEmail("123@145.com")); // numeric local part and domain name
assertTrue(Email.isValidEmail("a1+be.d@example1.com")); // mixture of alphanumeric and special characters
assertTrue(Email.isValidEmail("peter_jack@very-very-very-long-example.com")); // long domain name
assertTrue(Email.isValidEmail("if.you.dream.it_you.can.do.it@example.com")); // long local part
@@ -68,10 +68,10 @@ public void isValidEmail() {
@Test
public void equals() {
- Email email = new Email("valid@email");
+ Email email = new Email("valid@email.com");
// same values -> returns true
- assertTrue(email.equals(new Email("valid@email")));
+ assertTrue(email.equals(new Email("valid@email.com")));
// same object -> returns true
assertTrue(email.equals(email));
@@ -83,6 +83,6 @@ public void equals() {
assertFalse(email.equals(5.0f));
// different values -> returns false
- assertFalse(email.equals(new Email("other.valid@email")));
+ assertFalse(email.equals(new Email("other.valid@email.com")));
}
}
diff --git a/src/test/java/seedu/address/model/person/GenderTest.java b/src/test/java/seedu/address/model/person/GenderTest.java
new file mode 100644
index 00000000000..8ebeaa3e47e
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/GenderTest.java
@@ -0,0 +1,57 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class GenderTest {
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Gender(null));
+ }
+
+ @Test
+ public void constructor_invalidGender_throwsIllegalArgumentException() {
+ String invalidGender = "";
+ assertThrows(IllegalArgumentException.class, () -> new Gender(invalidGender));
+ }
+
+ @Test
+ public void isValidGender() {
+ // null gender
+ assertThrows(NullPointerException.class, () -> Gender.isValidGender(null));
+
+ // invalid gender
+ assertFalse(Gender.isValidGender("")); // empty string
+ assertFalse(Gender.isValidGender(" ")); // spaces only
+ assertFalse(Gender.isValidGender("^")); // only non-alphanumeric characters
+ assertFalse(Gender.isValidGender("alice*")); // contains non-alphanumeric characters
+
+ // valid gender
+ assertTrue(Gender.isValidGender("Female")); // alphabets only
+ assertTrue(Gender.isValidGender("Male")); // numbers only
+ assertTrue(Gender.isValidGender("Other")); // alphanumeric characters
+ }
+
+ @Test
+ public void equals() {
+ Gender gender = new Gender("Female");
+
+ // same values -> returns true
+ assertTrue(gender.equals(new Gender("Female")));
+
+ // same object -> returns true
+ assertTrue(gender.equals(gender));
+
+ // null -> returns false
+ assertFalse(gender.equals(null));
+
+ // different types -> returns false
+ assertFalse(gender.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(gender.equals(new Gender("Male")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
index 6b3fd90ade7..aa85242d7b9 100644
--- a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
+++ b/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
@@ -70,8 +70,8 @@ public void test_nameDoesNotContainKeywords_returnsFalse() {
// Keywords match phone, email and address, but does not match name
predicate = new NameContainsKeywordsPredicate(Arrays.asList("12345", "alice@email.com", "Main", "Street"));
- assertFalse(predicate.test(new PersonBuilder().withName("Alice").withPhone("12345")
- .withEmail("alice@email.com").withAddress("Main Street").build()));
+ assertFalse(predicate.test(new PersonBuilder().withName("Alice").withPhone("92345678")
+ .withEmail("alice@email.com").withAddress("Main Street/123456").build()));
}
@Test
diff --git a/src/test/java/seedu/address/model/person/NameTest.java b/src/test/java/seedu/address/model/person/NameTest.java
index 94e3dd726bd..7820172e779 100644
--- a/src/test/java/seedu/address/model/person/NameTest.java
+++ b/src/test/java/seedu/address/model/person/NameTest.java
@@ -31,11 +31,14 @@ public void isValidName() {
assertFalse(Name.isValidName("peter*")); // contains non-alphanumeric characters
// valid name
- assertTrue(Name.isValidName("peter jack")); // alphabets only
- assertTrue(Name.isValidName("12345")); // numbers only
- assertTrue(Name.isValidName("peter the 2nd")); // alphanumeric characters
- assertTrue(Name.isValidName("Capital Tan")); // with capital letters
- assertTrue(Name.isValidName("David Roger Jackson Ray Jr 2nd")); // long names
+ assertTrue(Name.isValidName("Peter Jack"));
+ assertTrue(Name.isValidName("Capital Tan"));
+ assertTrue(Name.isValidName("CapitalTan")); // no spaces
+ assertTrue(Name.isValidName("David Roger Jackson Ray Jr")); // long names
+ assertTrue(Name.isValidName("peter jack")); // non-capital lettes
+ assertTrue(Name.isValidName("Tiyanes S/O Selvaraj")); // names with special characters
+ assertTrue(Name.isValidName("Jean-Luc Picard"));
+ assertTrue(Name.isValidName("O'Connor"));
}
@Test
diff --git a/src/test/java/seedu/address/model/person/NationalityTest.java b/src/test/java/seedu/address/model/person/NationalityTest.java
new file mode 100644
index 00000000000..aadd89da36c
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/NationalityTest.java
@@ -0,0 +1,57 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class NationalityTest {
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Nationality(null));
+ }
+
+ @Test
+ public void constructor_invalidNationality_throwsIllegalArgumentException() {
+ String invalidNationality = "";
+ assertThrows(IllegalArgumentException.class, () -> new Nationality(invalidNationality));
+ }
+
+ @Test
+ public void isValidNationality() {
+ // null nationality
+ assertThrows(NullPointerException.class, () -> Nationality.isValidNationality(null));
+
+ // invalid nationality
+ assertFalse(Nationality.isValidNationality("")); // empty string
+ assertFalse(Nationality.isValidNationality(" ")); // spaces only
+ assertFalse(Nationality.isValidNationality("^")); // only non-alphanumeric characters
+ assertFalse(Nationality.isValidNationality("alice*")); // contains non-alphanumeric characters/ not in the list
+
+ // valid nationality
+ assertTrue(Nationality.isValidNationality("Bulgarian"));
+ assertTrue(Nationality.isValidNationality("American"));
+ assertTrue(Nationality.isValidNationality("Papua New Guinean"));
+ }
+
+ @Test
+ public void equals() {
+ Nationality nationality = new Nationality("Singaporean");
+
+ // same values -> returns true
+ assertTrue(nationality.equals(new Nationality("Singaporean")));
+
+ // same object -> returns true
+ assertTrue(nationality.equals(nationality));
+
+ // null -> returns false
+ assertFalse(nationality.equals(null));
+
+ // different types -> returns false
+ assertFalse(nationality.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(nationality.equals(new Nationality("Russian")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/NoteTest.java b/src/test/java/seedu/address/model/person/NoteTest.java
new file mode 100644
index 00000000000..1b0964315be
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/NoteTest.java
@@ -0,0 +1,31 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class NoteTest {
+
+ @Test
+ public void equals() {
+ Note note = new Note("Hello");
+
+ // same object -> returns true
+ assertTrue(note.equals(note));
+
+ // same values -> returns true
+ Note noteCopy = new Note(note.value);
+ assertTrue(note.equals(noteCopy));
+
+ // different types -> returns false
+ assertFalse(note.equals(1));
+
+ // null -> returns false
+ assertFalse(note.equals(null));
+
+ // different note -> returns false
+ Note differentNote = new Note("Bye");
+ assertFalse(note.equals(differentNote));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/NricTest.java b/src/test/java/seedu/address/model/person/NricTest.java
new file mode 100644
index 00000000000..a6d6052c8ec
--- /dev/null
+++ b/src/test/java/seedu/address/model/person/NricTest.java
@@ -0,0 +1,60 @@
+package seedu.address.model.person;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class NricTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Nric(null));
+ }
+
+ @Test
+ public void constructor_invalidNric_throwsIllegalArgumentException() {
+ String invalidNric = "";
+ assertThrows(IllegalArgumentException.class, () -> new Nric(invalidNric));
+ }
+
+ @Test
+ public void isValidNric() {
+ // null nric
+ assertThrows(NullPointerException.class, () -> Nric.isValidNric(null));
+
+ // invalid nric
+ assertFalse(Nric.isValidNric("")); // empty string
+ assertFalse(Nric.isValidNric(" ")); // spaces only
+ assertFalse(Nric.isValidNric("^")); // only non-alphanumeric characters
+ assertFalse(Nric.isValidNric("A9385712A*")); // starts with an undefined alphabet
+ assertFalse(Nric.isValidNric("S9385712a*")); // ends with non-capital letter
+
+ // valid nric
+ assertTrue(Nric.isValidNric("T0928347A")); // correct format only
+ assertTrue(Nric.isValidNric("S0239481Z")); // try using S
+ assertTrue(Nric.isValidNric("F9381739G")); // try using F
+ assertTrue(Nric.isValidNric("G1234567P")); // try using G
+ }
+
+ @Test
+ public void equals() {
+ Nric nric = new Nric("T0123456A");
+
+ // same values -> returns true
+ assertTrue(nric.equals(new Nric("T0123456A")));
+
+ // same object -> returns true
+ assertTrue(nric.equals(nric));
+
+ // null -> returns false
+ assertFalse(nric.equals(null));
+
+ // different types -> returns false
+ assertFalse(nric.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(nric.equals(new Nric("T0987654A")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/seedu/address/model/person/PersonTest.java
index 31a10d156c9..05a437d2025 100644
--- a/src/test/java/seedu/address/model/person/PersonTest.java
+++ b/src/test/java/seedu/address/model/person/PersonTest.java
@@ -4,14 +4,21 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DATE_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DOB_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GENDER_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NATIONALITY_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NRIC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_MARKETING;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.ALICE;
import static seedu.address.testutil.TypicalPersons.BOB;
+import java.util.Arrays;
+
import org.junit.jupiter.api.Test;
import seedu.address.testutil.PersonBuilder;
@@ -21,7 +28,8 @@ public class PersonTest {
@Test
public void asObservableList_modifyList_throwsUnsupportedOperationException() {
Person person = new PersonBuilder().build();
- assertThrows(UnsupportedOperationException.class, () -> person.getTags().remove(0));
+ assertThrows(UnsupportedOperationException.class, ()
+ -> Arrays.asList(person.getTag().getValue()).remove(0));
}
@Test
@@ -32,23 +40,24 @@ public void isSamePerson() {
// null -> returns false
assertFalse(ALICE.isSamePerson(null));
- // same name, all other attributes different -> returns true
- Person editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB)
- .withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND).build();
+ // same nric, all other attributes different -> returns true
+ Person editedAlice = new PersonBuilder(BOB).withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB)
+ .withNric(ALICE.getNric().toString())
+ .withGender(VALID_GENDER_BOB).withDob(VALID_DOB_BOB)
+ .withDateOfJoining(VALID_DATE_BOB)
+ .withNationality(VALID_NATIONALITY_BOB)
+ .withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_MARKETING).build();
assertTrue(ALICE.isSamePerson(editedAlice));
- // different name, all other attributes same -> returns false
- editedAlice = new PersonBuilder(ALICE).withName(VALID_NAME_BOB).build();
+ // different nric, all other attributes same -> returns false
+ editedAlice = new PersonBuilder(ALICE).withNric(VALID_NRIC_BOB).build();
assertFalse(ALICE.isSamePerson(editedAlice));
- // name differs in case, all other attributes same -> returns false
- Person editedBob = new PersonBuilder(BOB).withName(VALID_NAME_BOB.toLowerCase()).build();
- assertFalse(BOB.isSamePerson(editedBob));
+ // nric differs in case, all other attributes same -> returns false
+ assertThrows(IllegalArgumentException.class, () -> new Nric(VALID_NRIC_BOB.toLowerCase()));
- // name has trailing spaces, all other attributes same -> returns false
- String nameWithTrailingSpaces = VALID_NAME_BOB + " ";
- editedBob = new PersonBuilder(BOB).withName(nameWithTrailingSpaces).build();
- assertFalse(BOB.isSamePerson(editedBob));
+ // nric has trailing spaces, all other attributes same -> returns false
+ assertThrows(IllegalArgumentException.class, () -> new Nric(VALID_NRIC_BOB + " "));
}
@Test
@@ -81,19 +90,43 @@ public void equals() {
editedAlice = new PersonBuilder(ALICE).withEmail(VALID_EMAIL_BOB).build();
assertFalse(ALICE.equals(editedAlice));
+ // different nric -> returns false
+ editedAlice = new PersonBuilder(ALICE).withNric(VALID_NRIC_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different gender -> returns false
+ editedAlice = new PersonBuilder(ALICE).withGender(VALID_GENDER_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different dob -> returns false
+ editedAlice = new PersonBuilder(ALICE).withDob(VALID_DOB_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different dateOfJoining -> returns false
+ editedAlice = new PersonBuilder(ALICE).withDateOfJoining(VALID_DATE_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different nationality -> returns false
+ editedAlice = new PersonBuilder(ALICE).withNationality(VALID_NATIONALITY_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
// different address -> returns false
editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).build();
assertFalse(ALICE.equals(editedAlice));
// different tags -> returns false
- editedAlice = new PersonBuilder(ALICE).withTags(VALID_TAG_HUSBAND).build();
+ editedAlice = new PersonBuilder(ALICE).withTags(VALID_TAG_MARKETING).build();
assertFalse(ALICE.equals(editedAlice));
}
@Test
public void toStringMethod() {
String expected = Person.class.getCanonicalName() + "{name=" + ALICE.getName() + ", phone=" + ALICE.getPhone()
- + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", tags=" + ALICE.getTags() + "}";
+ + ", email=" + ALICE.getEmail() + ", nric=" + ALICE.getNric()
+ + ", gender=" + ALICE.getGender() + ", dob=" + ALICE.getDob()
+ + ", dateOfJoining=" + ALICE.getDateOfJoining()
+ + ", nationality=" + ALICE.getNationality() + ", address=" + ALICE.getAddress()
+ + ", tags=" + ALICE.getTag() + "}";
assertEquals(expected, ALICE.toString());
}
}
diff --git a/src/test/java/seedu/address/model/person/PhoneTest.java b/src/test/java/seedu/address/model/person/PhoneTest.java
index deaaa5ba190..d5d3b29e574 100644
--- a/src/test/java/seedu/address/model/person/PhoneTest.java
+++ b/src/test/java/seedu/address/model/person/PhoneTest.java
@@ -33,17 +33,18 @@ public void isValidPhone() {
assertFalse(Phone.isValidPhone("9312 1534")); // spaces within digits
// valid phone numbers
- assertTrue(Phone.isValidPhone("911")); // exactly 3 numbers
assertTrue(Phone.isValidPhone("93121534"));
- assertTrue(Phone.isValidPhone("124293842033123")); // long phone numbers
+ assertTrue(Phone.isValidPhone("93285928"));
+ assertTrue(Phone.isValidPhone("81920374"));
+ assertTrue(Phone.isValidPhone("69121534"));
}
@Test
public void equals() {
- Phone phone = new Phone("999");
+ Phone phone = new Phone("99998888");
// same values -> returns true
- assertTrue(phone.equals(new Phone("999")));
+ assertTrue(phone.equals(new Phone("99998888")));
// same object -> returns true
assertTrue(phone.equals(phone));
@@ -55,6 +56,6 @@ public void equals() {
assertFalse(phone.equals(5.0f));
// different values -> returns false
- assertFalse(phone.equals(new Phone("995")));
+ assertFalse(phone.equals(new Phone("99998887")));
}
}
diff --git a/src/test/java/seedu/address/model/person/UniquePersonListTest.java b/src/test/java/seedu/address/model/person/UniquePersonListTest.java
index 17ae501df08..90b742c091f 100644
--- a/src/test/java/seedu/address/model/person/UniquePersonListTest.java
+++ b/src/test/java/seedu/address/model/person/UniquePersonListTest.java
@@ -4,7 +4,7 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_MARKETING;
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.ALICE;
import static seedu.address.testutil.TypicalPersons.BOB;
@@ -42,7 +42,7 @@ public void contains_personInList_returnsTrue() {
@Test
public void contains_personWithSameIdentityFieldsInList_returnsTrue() {
uniquePersonList.add(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
+ Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_MARKETING)
.build();
assertTrue(uniquePersonList.contains(editedAlice));
}
@@ -85,7 +85,7 @@ public void setPerson_editedPersonIsSamePerson_success() {
@Test
public void setPerson_editedPersonHasSameIdentity_success() {
uniquePersonList.add(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
+ Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_MARKETING)
.build();
uniquePersonList.setPerson(ALICE, editedAlice);
UniquePersonList expectedUniquePersonList = new UniquePersonList();
diff --git a/src/test/java/seedu/address/model/tag/DepartmentTest.java b/src/test/java/seedu/address/model/tag/DepartmentTest.java
new file mode 100644
index 00000000000..88d8e04438c
--- /dev/null
+++ b/src/test/java/seedu/address/model/tag/DepartmentTest.java
@@ -0,0 +1,81 @@
+package seedu.address.model.tag;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class DepartmentTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Department(null));
+ }
+
+ @Test
+ public void constructor_invalidDepartment_throwsIllegalArgumentException() {
+ String invalidDepartment = "";
+ assertThrows(IllegalArgumentException.class, () -> new Department(invalidDepartment));
+ }
+
+ @Test
+ public void isValidDepartment() {
+ // null department
+ assertThrows(NullPointerException.class, () -> Department.isValidDepartment(null));
+
+ // invalid departments
+ assertFalse(Department.isValidDepartment(""));
+ assertFalse(Department.isValidDepartment("#Human Resources"));
+
+ // valid departments
+ assertTrue(Department.isValidDepartment("hr"));
+ assertTrue(Department.isValidDepartment("Human Resources"));
+ assertTrue(Department.isValidDepartment("Human Resources")); // extra space between words
+ assertTrue(Department.isValidDepartment("Marketing"));
+ assertTrue(Department.isValidDepartment("Marketing ")); // extra spaces after word
+ assertTrue(Department.isValidDepartment(" Marketing")); // extra spaces before word
+ assertTrue(Department.isValidDepartment("marketing")); // non capital letter
+ assertTrue(Department.isValidDepartment("marKEting")); // different capitalizations
+ }
+
+ @Test
+ public void isValidDepartmentInput() {
+ // null department
+ assertThrows(NullPointerException.class, () -> Department.isValidDepartmentInput(null));
+
+ // invalid departments
+ assertFalse(Department.isValidDepartmentInput(""));
+ assertFalse(Department.isValidDepartmentInput("#Human Resources"));
+
+ // valid departments
+ assertTrue(Department.isValidDepartmentInput("hr"));
+ assertTrue(Department.isValidDepartmentInput("Human Resources"));
+ assertTrue(Department.isValidDepartmentInput("Human Resources")); // extra space between words
+ assertTrue(Department.isValidDepartmentInput("Marketing"));
+ assertTrue(Department.isValidDepartmentInput("Marketing ")); // extra spaces after word
+ assertTrue(Department.isValidDepartmentInput(" Marketing")); // extra spaces before word
+ assertTrue(Department.isValidDepartmentInput("marketing")); // non capital letter
+ assertTrue(Department.isValidDepartmentInput("marKEting")); // different capitalizations
+ }
+
+ @Test
+ public void equals() {
+ Department department = new Department("Human Resources");
+
+ // same values -> returns true
+ assertTrue(department.equals(new Department("Human Resources")));
+
+ // same object -> returns true
+ assertTrue(department.equals(department));
+
+ // null -> returns false
+ assertFalse(department.equals(null));
+
+ // different types -> returns false
+ assertFalse(department.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(department.equals(new Department("Marketing")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/tag/EmploymentTypeTest.java b/src/test/java/seedu/address/model/tag/EmploymentTypeTest.java
new file mode 100644
index 00000000000..302dda88725
--- /dev/null
+++ b/src/test/java/seedu/address/model/tag/EmploymentTypeTest.java
@@ -0,0 +1,59 @@
+package seedu.address.model.tag;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class EmploymentTypeTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new EmploymentType(null));
+ }
+
+ @Test
+ public void constructor_invalidEmploymentType_throwsIllegalArgumentException() {
+ String invalidEmploymentType = "";
+ assertThrows(IllegalArgumentException.class, () -> new EmploymentType(invalidEmploymentType));
+ }
+
+ @Test
+ public void isValidEmploymentType() {
+ // null employment type
+ assertThrows(NullPointerException.class, () -> EmploymentType.isValidEmploymentType(null));
+
+ // invalid employment types
+ assertFalse(EmploymentType.isValidEmploymentType(""));
+ assertFalse(EmploymentType.isValidEmploymentType("None"));
+
+ // valid employment types
+ assertTrue(EmploymentType.isValidEmploymentType("Full-Time"));
+ assertTrue(EmploymentType.isValidEmploymentType("Part-Time"));
+ assertTrue(EmploymentType.isValidEmploymentType("Part-Time"));
+ assertTrue(EmploymentType.isValidEmploymentType(" Part-Time")); // extra space before
+ assertTrue(EmploymentType.isValidEmploymentType("Part-Time ")); // extra space after
+ assertTrue(EmploymentType.isValidEmploymentType("part-time")); // non capital
+ }
+
+ @Test
+ public void equals() {
+ EmploymentType employmentType = new EmploymentType("Full-Time");
+
+ // same values -> returns true
+ assertTrue(employmentType.equals(new EmploymentType("Full-Time")));
+
+ // same object -> returns true
+ assertTrue(employmentType.equals(employmentType));
+
+ // null -> returns false
+ assertFalse(employmentType.equals(null));
+
+ // different types -> returns false
+ assertFalse(employmentType.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(employmentType.equals(new EmploymentType("Part-Time")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/tag/JobTitleTest.java b/src/test/java/seedu/address/model/tag/JobTitleTest.java
new file mode 100644
index 00000000000..7083d0c2c60
--- /dev/null
+++ b/src/test/java/seedu/address/model/tag/JobTitleTest.java
@@ -0,0 +1,59 @@
+package seedu.address.model.tag;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class JobTitleTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new JobTitle(null));
+ }
+
+ @Test
+ public void constructor_invalidJobTitle_throwsIllegalArgumentException() {
+ String invalidJobTitle = "";
+ assertThrows(IllegalArgumentException.class, () -> new JobTitle(invalidJobTitle));
+ }
+
+ @Test
+ public void isValidJobTitle() {
+ // null job title
+ assertThrows(NullPointerException.class, () -> JobTitle.isValidJobTitle(null));
+
+ // invalid job titles
+ assertFalse(JobTitle.isValidJobTitle(""));
+ assertFalse(JobTitle.isValidJobTitle("Teacher"));
+
+ // valid job titles
+ assertTrue(JobTitle.isValidJobTitle("HR Coordinator"));
+ assertTrue(JobTitle.isValidJobTitle("Marketing Specialist"));
+ assertTrue(JobTitle.isValidJobTitle("HR Coordinator")); // extra space between words
+ assertTrue(JobTitle.isValidJobTitle("HR Coordinator ")); // extra space behind
+ assertTrue(JobTitle.isValidJobTitle(" HR Coordinator")); // extra space in front
+ assertTrue(JobTitle.isValidJobTitle("hr Coordinator")); // non capital
+ }
+
+ @Test
+ public void equals() {
+ JobTitle jobTitle = new JobTitle("HR Coordinator");
+
+ // same values -> returns true
+ assertTrue(jobTitle.equals(new JobTitle("HR Coordinator")));
+
+ // same object -> returns true
+ assertTrue(jobTitle.equals(jobTitle));
+
+ // null -> returns false
+ assertFalse(jobTitle.equals(null));
+
+ // different types -> returns false
+ assertFalse(jobTitle.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(jobTitle.equals(new JobTitle("Marketing Specialist")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/tag/TagTest.java b/src/test/java/seedu/address/model/tag/TagTest.java
index 64d07d79ee2..3ab47b07ba3 100644
--- a/src/test/java/seedu/address/model/tag/TagTest.java
+++ b/src/test/java/seedu/address/model/tag/TagTest.java
@@ -8,13 +8,14 @@ public class TagTest {
@Test
public void constructor_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> new Tag(null));
+ assertThrows(NullPointerException.class, () -> new Tag(null, null, null));
}
@Test
public void constructor_invalidTagName_throwsIllegalArgumentException() {
- String invalidTagName = "";
- assertThrows(IllegalArgumentException.class, () -> new Tag(invalidTagName));
+ EmploymentType employmentType = new EmploymentType("Full-Time");
+ JobTitle jobTitle = new JobTitle("HR Coordinator");
+ assertThrows(NullPointerException.class, () -> new Tag(null, employmentType, jobTitle));
}
@Test
diff --git a/src/test/java/seedu/address/model/util/SampleDataUtilTest.java b/src/test/java/seedu/address/model/util/SampleDataUtilTest.java
new file mode 100644
index 00000000000..037db49b6f1
--- /dev/null
+++ b/src/test/java/seedu/address/model/util/SampleDataUtilTest.java
@@ -0,0 +1,58 @@
+package seedu.address.model.util;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.person.Person;
+import seedu.address.model.tag.Department;
+import seedu.address.model.tag.EmploymentType;
+import seedu.address.model.tag.JobTitle;
+import seedu.address.model.tag.Tag;
+
+public class SampleDataUtilTest {
+
+ @Test
+ public void getSamplePersons() {
+ Person[] samplePersons = SampleDataUtil.getSamplePersons();
+
+ assertTrue(samplePersons.length == 6);
+
+ Person person = samplePersons[0];
+ assertEquals("Alex Yeoh", person.getName().fullName);
+ assertEquals("87438807", person.getPhone().value);
+ assertEquals("alexyeoh@example.com", person.getEmail().value);
+ assertEquals("S9019283Z", person.getNric().value);
+ assertEquals("Male", person.getGender().value);
+ assertEquals("01-Oct-1990", person.getDob().value);
+ assertEquals("12-Feb-2025", person.getDateOfJoining().value);
+ assertEquals("Singaporean", person.getNationality().value);
+ assertEquals("Blk 30 Geylang Street 29, #06-40/101010", person.getAddress().value);
+ assertEquals("Human Resources", person.getTag().getValue()[0]);
+ assertEquals("Full-Time", person.getTag().getValue()[1]);
+ assertEquals("HR Coordinator", person.getTag().getValue()[2]);
+ }
+
+ @Test
+ public void getSampleAddressBook() {
+ ReadOnlyAddressBook sampleAddressBook = SampleDataUtil.getSampleAddressBook();
+
+ assertEquals(SampleDataUtil.getSamplePersons().length, sampleAddressBook.getPersonList().size());
+
+ Person personInBook = sampleAddressBook.getPersonList().get(0);
+ Person samplePerson = SampleDataUtil.getSamplePersons()[0];
+ assertEquals(samplePerson, personInBook);
+ }
+
+ @Test
+ public void getTag() {
+ Department department = new Department("Human Resources");
+ EmploymentType employmentType = new EmploymentType("Full-Time");
+ JobTitle jobTitle = new JobTitle("HR Coordinator");
+ Tag expectedTag = new Tag(department, employmentType, jobTitle);
+ assertEquals(expectedTag,
+ SampleDataUtil.getTag("Human Resources", "Full-Time", "HR Coordinator"));
+ }
+}
diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
index 83b11331cdb..8f3744c3f74 100644
--- a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
+++ b/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
@@ -5,16 +5,17 @@
import static seedu.address.testutil.Assert.assertThrows;
import static seedu.address.testutil.TypicalPersons.BENSON;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
import org.junit.jupiter.api.Test;
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.model.person.Address;
+import seedu.address.model.person.DateOfJoining;
+import seedu.address.model.person.Dob;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Gender;
import seedu.address.model.person.Name;
+import seedu.address.model.person.Nationality;
+import seedu.address.model.person.Nric;
import seedu.address.model.person.Phone;
public class JsonAdaptedPersonTest {
@@ -22,15 +23,24 @@ public class JsonAdaptedPersonTest {
private static final String INVALID_PHONE = "+651234";
private static final String INVALID_ADDRESS = " ";
private static final String INVALID_EMAIL = "example.com";
- private static final String INVALID_TAG = "#friend";
+ private static final String INVALID_NRIC = "T03171800";
+ private static final String INVALID_GENDER = "test";
+ private static final String INVALID_DOB = "2020 01 01";
+ private static final String INVALID_DATE = "2020/01-01";
+ private static final String INVALID_NATIONALITY = "singapore";
+ private static final String[] INVALID_TAG = new String[] {"Teaching", "Full-Time", "HR Coordinator"};
private static final String VALID_NAME = BENSON.getName().toString();
private static final String VALID_PHONE = BENSON.getPhone().toString();
private static final String VALID_EMAIL = BENSON.getEmail().toString();
+ private static final String VALID_NRIC = BENSON.getNric().toString();
+ private static final String VALID_GENDER = BENSON.getGender().toString();
+ private static final String VALID_DOB = BENSON.getDob().toString();
+ private static final String VALID_DATE = BENSON.getDateOfJoining().toString();
+ private static final String VALID_NATIONALITY = BENSON.getNationality().toString();
private static final String VALID_ADDRESS = BENSON.getAddress().toString();
- private static final List VALID_TAGS = BENSON.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList());
+ private static final String VALID_NOTE = BENSON.getNote().toString();
+ private static final String[] VALID_TAGS = BENSON.getTag().getValue();
@Test
public void toModelType_validPersonDetails_returnsPerson() throws Exception {
@@ -41,14 +51,17 @@ public void toModelType_validPersonDetails_returnsPerson() throws Exception {
@Test
public void toModelType_invalidName_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
String expectedMessage = Name.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullName_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@@ -56,14 +69,17 @@ public void toModelType_nullName_throwsIllegalValueException() {
@Test
public void toModelType_invalidPhone_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
String expectedMessage = Phone.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullPhone_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@@ -71,39 +87,134 @@ public void toModelType_nullPhone_throwsIllegalValueException() {
@Test
public void toModelType_invalidEmail_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
String expectedMessage = Email.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullEmail_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
+ @Test
+ public void toModelType_invalidNric_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
+ String expectedMessage = Nric.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullNric_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Nric.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_invalidGender_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, INVALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
+ String expectedMessage = Gender.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullGender_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, null, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Gender.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_invalidDob_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, INVALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
+ String expectedMessage = Dob.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullDob_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, null,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Dob.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_invalidDate_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ INVALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
+ String expectedMessage = DateOfJoining.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullDate_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ null, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, DateOfJoining.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_invalidNationality_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, INVALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
+ String expectedMessage = Nationality.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullNationality_throwsIllegalValueException() {
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, null, VALID_ADDRESS, VALID_NOTE, VALID_TAGS);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Nationality.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
+ }
+
@Test
public void toModelType_invalidAddress_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_ADDRESS, VALID_TAGS);
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, INVALID_ADDRESS, VALID_NOTE, VALID_TAGS);
String expectedMessage = Address.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullAddress_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_TAGS);
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, null, VALID_NOTE, VALID_TAGS);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_invalidTags_throwsIllegalValueException() {
- List invalidTags = new ArrayList<>(VALID_TAGS);
- invalidTags.add(new JsonAdaptedTag(INVALID_TAG));
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags);
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_NRIC, VALID_GENDER, VALID_DOB,
+ VALID_DATE, VALID_NATIONALITY, VALID_ADDRESS, VALID_NOTE, INVALID_TAG);
assertThrows(IllegalValueException.class, person::toModelType);
}
diff --git a/src/test/java/seedu/address/storage/JsonAdaptedTagTest.java b/src/test/java/seedu/address/storage/JsonAdaptedTagTest.java
new file mode 100644
index 00000000000..bcee4fe554c
--- /dev/null
+++ b/src/test/java/seedu/address/storage/JsonAdaptedTagTest.java
@@ -0,0 +1,57 @@
+package seedu.address.storage;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.tag.Department;
+import seedu.address.model.tag.EmploymentType;
+import seedu.address.model.tag.JobTitle;
+import seedu.address.model.tag.Tag;
+
+public class JsonAdaptedTagTest {
+ private static final String VALID_DEPARTMENT = "Human Resources";
+ private static final String VALID_EMPLOYMENT_TYPE = "Full-Time";
+ private static final String VALID_JOB_TITLE = "HR Coordinator";
+ private static final String INVALID_DEPARTMENT = "#Human Resources";
+
+ @Test
+ public void toModelType_validTag() throws Exception {
+ String[] tag = new String[] {VALID_DEPARTMENT, VALID_EMPLOYMENT_TYPE, VALID_JOB_TITLE};
+ JsonAdaptedTag jsonAdaptedTag = new JsonAdaptedTag(tag);
+ Tag expectedTag = new Tag(
+ new Department(VALID_DEPARTMENT),
+ new EmploymentType(VALID_EMPLOYMENT_TYPE),
+ new JobTitle(VALID_JOB_TITLE)
+ );
+ assertEquals(expectedTag, jsonAdaptedTag.toModelType());
+ }
+
+ @Test
+ public void toModelType_invalidTag_throwsIllegalValueException() {
+ String[] tag = new String[] {INVALID_DEPARTMENT, VALID_EMPLOYMENT_TYPE, VALID_JOB_TITLE};
+ JsonAdaptedTag jsonAdaptedTag = new JsonAdaptedTag(tag);
+ assertThrows(IllegalValueException.class, jsonAdaptedTag::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullTag_throwsIllegalValueException() {
+ JsonAdaptedTag jsonAdaptedTag = new JsonAdaptedTag((String[]) null);
+ assertThrows(NullPointerException.class, jsonAdaptedTag::toModelType);
+ }
+
+ @Test
+ public void constructor_validTag() {
+ Department department = new Department(VALID_DEPARTMENT);
+ EmploymentType employmentType = new EmploymentType(VALID_EMPLOYMENT_TYPE);
+ JobTitle jobTitle = new JobTitle(VALID_JOB_TITLE);
+ Tag tag = new Tag(department, employmentType, jobTitle);
+ JsonAdaptedTag jsonAdaptedTag = new JsonAdaptedTag(tag);
+ String[] expectedTag = new String[] {VALID_DEPARTMENT, VALID_EMPLOYMENT_TYPE, VALID_JOB_TITLE};
+ assertEquals(expectedTag[0], jsonAdaptedTag.getTagName()[0]);
+ assertEquals(expectedTag[1], jsonAdaptedTag.getTagName()[1]);
+ assertEquals(expectedTag[2], jsonAdaptedTag.getTagName()[2]);
+ }
+}
diff --git a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java
index ed0a413526a..3415bc0ca68 100644
--- a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java
+++ b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java
@@ -73,7 +73,7 @@ public void readUserPrefs_extraValuesInFile_extraValuesIgnored() throws DataLoad
private UserPrefs getTypicalUserPrefs() {
UserPrefs userPrefs = new UserPrefs();
userPrefs.setGuiSettings(new GuiSettings(1000, 500, 300, 100));
- userPrefs.setAddressBookFilePath(Paths.get("addressbook.json"));
+ userPrefs.setAddressBookFilePath(Paths.get("hrelper.json"));
return userPrefs;
}
diff --git a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
index 4584bd5044e..f94f673aebf 100644
--- a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
+++ b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
@@ -1,15 +1,18 @@
package seedu.address.testutil;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.model.person.Address;
+import seedu.address.model.person.DateOfJoining;
+import seedu.address.model.person.Dob;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Gender;
import seedu.address.model.person.Name;
+import seedu.address.model.person.Nationality;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.tag.Department;
+import seedu.address.model.tag.EmploymentType;
+import seedu.address.model.tag.JobTitle;
import seedu.address.model.tag.Tag;
/**
@@ -35,8 +38,12 @@ public EditPersonDescriptorBuilder(Person person) {
descriptor.setName(person.getName());
descriptor.setPhone(person.getPhone());
descriptor.setEmail(person.getEmail());
+ descriptor.setGender(person.getGender());
+ descriptor.setDob(person.getDob());
+ descriptor.setDateOfJoining(person.getDateOfJoining());
+ descriptor.setNationality(person.getNationality());
descriptor.setAddress(person.getAddress());
- descriptor.setTags(person.getTags());
+ descriptor.setTag(person.getTag());
}
/**
@@ -63,6 +70,38 @@ public EditPersonDescriptorBuilder withEmail(String email) {
return this;
}
+ /**
+ * Sets the {@code Gender} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPersonDescriptorBuilder withGender(String gender) {
+ descriptor.setGender(new Gender(gender));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Dob} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPersonDescriptorBuilder withDob(String dob) {
+ descriptor.setDob(new Dob(dob));
+ return this;
+ }
+
+ /**
+ * Sets the {@code DateOfJoining} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPersonDescriptorBuilder withDateOfJoining(String dateOfJoining) {
+ descriptor.setDateOfJoining(new DateOfJoining(dateOfJoining));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Nationality} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPersonDescriptorBuilder withNationality(String nationality) {
+ descriptor.setNationality(new Nationality(nationality));
+ return this;
+ }
+
/**
* Sets the {@code Address} of the {@code EditPersonDescriptor} that we are building.
*/
@@ -75,9 +114,12 @@ public EditPersonDescriptorBuilder withAddress(String address) {
* Parses the {@code tags} into a {@code Set} and set it to the {@code EditPersonDescriptor}
* that we are building.
*/
- public EditPersonDescriptorBuilder withTags(String... tags) {
- Set tagSet = Stream.of(tags).map(Tag::new).collect(Collectors.toSet());
- descriptor.setTags(tagSet);
+ public EditPersonDescriptorBuilder withTags(String tags) {
+ String[] tagList = tags.split("/");
+ Department department = new Department(tagList[0]);
+ EmploymentType employmentType = new EmploymentType(tagList[1]);
+ JobTitle jobTitle = new JobTitle(tagList[2]);
+ descriptor.setTag(new Tag(department, employmentType, jobTitle));
return this;
}
diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java
index 6be381d39ba..35e536237b7 100644
--- a/src/test/java/seedu/address/testutil/PersonBuilder.java
+++ b/src/test/java/seedu/address/testutil/PersonBuilder.java
@@ -1,15 +1,20 @@
package seedu.address.testutil;
-import java.util.HashSet;
-import java.util.Set;
-
import seedu.address.model.person.Address;
+import seedu.address.model.person.DateOfJoining;
+import seedu.address.model.person.Dob;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Gender;
import seedu.address.model.person.Name;
+import seedu.address.model.person.Nationality;
+import seedu.address.model.person.Note;
+import seedu.address.model.person.Nric;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
+import seedu.address.model.tag.Department;
+import seedu.address.model.tag.EmploymentType;
+import seedu.address.model.tag.JobTitle;
import seedu.address.model.tag.Tag;
-import seedu.address.model.util.SampleDataUtil;
/**
* A utility class to help with building Person objects.
@@ -19,13 +24,28 @@ public class PersonBuilder {
public static final String DEFAULT_NAME = "Amy Bee";
public static final String DEFAULT_PHONE = "85355255";
public static final String DEFAULT_EMAIL = "amy@gmail.com";
- public static final String DEFAULT_ADDRESS = "123, Jurong West Ave 6, #08-111";
+ public static final String DEFAULT_NRIC = "S9134567A";
+ public static final String DEFAULT_GENDER = "Female";
+ public static final String DEFAULT_DOB = "01-Jan-2020";
+ public static final String DEFAULT_DATE = "17-Mar-2025";
+ public static final String DEFAULT_NATIONALITY = "Singaporean";
+ public static final String DEFAULT_ADDRESS = "123, Jurong West Ave 6, #08-111/098726";
+ public static final String DEFAULT_DEPARTMENT = "Finance";
+ public static final String DEFAULT_EMPLOYMENT_TYPE = "Full-Time";
+ public static final String DEFAULT_JOB_TITLE = "Financial Analyst";
+ public static final String DEFAULT_NOTE = "She likes aardvarks.";
private Name name;
private Phone phone;
private Email email;
+ private Nric nric;
+ private Gender gender;
+ private Dob dob;
+ private DateOfJoining dateOfJoining;
+ private Nationality nationality;
private Address address;
- private Set tags;
+ private Note note;
+ private Tag tag;
/**
* Creates a {@code PersonBuilder} with the default details.
@@ -34,8 +54,17 @@ public PersonBuilder() {
name = new Name(DEFAULT_NAME);
phone = new Phone(DEFAULT_PHONE);
email = new Email(DEFAULT_EMAIL);
+ nric = new Nric(DEFAULT_NRIC);
+ gender = new Gender(DEFAULT_GENDER);
+ dob = new Dob(DEFAULT_DOB);
+ dateOfJoining = new DateOfJoining(DEFAULT_DATE);
+ nationality = new Nationality(DEFAULT_NATIONALITY);
address = new Address(DEFAULT_ADDRESS);
- tags = new HashSet<>();
+ Department department = new Department(DEFAULT_DEPARTMENT);
+ EmploymentType employmentType = new EmploymentType(DEFAULT_EMPLOYMENT_TYPE);
+ JobTitle jobTitle = new JobTitle(DEFAULT_JOB_TITLE);
+ tag = new Tag(department, employmentType, jobTitle);
+ note = new Note(DEFAULT_NOTE);
}
/**
@@ -45,8 +74,14 @@ public PersonBuilder(Person personToCopy) {
name = personToCopy.getName();
phone = personToCopy.getPhone();
email = personToCopy.getEmail();
+ nric = personToCopy.getNric();
+ gender = personToCopy.getGender();
+ dob = personToCopy.getDob();
+ dateOfJoining = personToCopy.getDateOfJoining();
+ nationality = personToCopy.getNationality();
address = personToCopy.getAddress();
- tags = new HashSet<>(personToCopy.getTags());
+ note = personToCopy.getNote();
+ tag = personToCopy.getTag();
}
/**
@@ -60,8 +95,12 @@ public PersonBuilder withName(String name) {
/**
* Parses the {@code tags} into a {@code Set} and set it to the {@code Person} that we are building.
*/
- public PersonBuilder withTags(String ... tags) {
- this.tags = SampleDataUtil.getTagSet(tags);
+ public PersonBuilder withTags(String tags) {
+ String[] tagList = tags.split("/");
+ Department department = new Department(tagList[0]);
+ EmploymentType employmentType = new EmploymentType(tagList[1]);
+ JobTitle jobTitle = new JobTitle(tagList[2]);
+ this.tag = new Tag(department, employmentType, jobTitle);
return this;
}
@@ -89,8 +128,56 @@ public PersonBuilder withEmail(String email) {
return this;
}
- public Person build() {
- return new Person(name, phone, email, address, tags);
+ /**
+ * Sets the {@code Nric} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withNric(String nric) {
+ this.nric = new Nric(nric);
+ return this;
}
+ /**
+ * Sets the {@code Gender} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withGender(String gender) {
+ this.gender = new Gender(gender);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Dob} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withDob(String dob) {
+ this.dob = new Dob(dob);
+ return this;
+ }
+
+ /**
+ * Sets the {@code DateOfJoining} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withDateOfJoining(String dateOfJoining) {
+ this.dateOfJoining = new DateOfJoining(dateOfJoining);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Nationality} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withNationality(String nationality) {
+ this.nationality = new Nationality(nationality);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Note} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withNote(String note) {
+ this.note = new Note(note);
+ return this;
+ }
+
+
+ public Person build() {
+ return new Person(name, phone, email, nric, gender, dob, dateOfJoining, nationality, address, note, tag);
+ }
}
diff --git a/src/test/java/seedu/address/testutil/PersonUtil.java b/src/test/java/seedu/address/testutil/PersonUtil.java
index 90849945183..703e93e7599 100644
--- a/src/test/java/seedu/address/testutil/PersonUtil.java
+++ b/src/test/java/seedu/address/testutil/PersonUtil.java
@@ -1,17 +1,19 @@
package seedu.address.testutil;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DOB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GENDER;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NATIONALITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NRIC;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import java.util.Set;
-
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.model.person.Person;
-import seedu.address.model.tag.Tag;
/**
* A utility class for Person.
@@ -33,10 +35,17 @@ public static String getPersonDetails(Person person) {
sb.append(PREFIX_NAME + person.getName().fullName + " ");
sb.append(PREFIX_PHONE + person.getPhone().value + " ");
sb.append(PREFIX_EMAIL + person.getEmail().value + " ");
+ sb.append(PREFIX_NRIC + person.getNric().value + " ");
+ sb.append(PREFIX_GENDER + person.getGender().value + " ");
+ sb.append(PREFIX_DOB + person.getDob().value + " ");
+ sb.append(PREFIX_DATE + person.getDateOfJoining().value + " ");
+ sb.append(PREFIX_NATIONALITY + person.getNationality().value + " ");
sb.append(PREFIX_ADDRESS + person.getAddress().value + " ");
- person.getTags().stream().forEach(
- s -> sb.append(PREFIX_TAG + s.tagName + " ")
- );
+ String[] tagList = person.getTag().getValue();
+ String department = tagList[0];
+ String employmentType = tagList[1];
+ String jobTitle = tagList[2];
+ sb.append(PREFIX_TAG + department + "/" + employmentType + "/" + jobTitle);
return sb.toString();
}
@@ -48,15 +57,19 @@ public static String getEditPersonDescriptorDetails(EditPersonDescriptor descrip
descriptor.getName().ifPresent(name -> sb.append(PREFIX_NAME).append(name.fullName).append(" "));
descriptor.getPhone().ifPresent(phone -> sb.append(PREFIX_PHONE).append(phone.value).append(" "));
descriptor.getEmail().ifPresent(email -> sb.append(PREFIX_EMAIL).append(email.value).append(" "));
+ descriptor.getGender().ifPresent(gender -> sb.append(PREFIX_GENDER).append(gender.value).append(" "));
+ descriptor.getDob().ifPresent(dob -> sb.append(PREFIX_DOB).append(dob.value).append(" "));
+ descriptor.getDateOfJoining().ifPresent(dateOfJoining -> sb.append(PREFIX_DATE)
+ .append(dateOfJoining.value).append(" "));
+ descriptor.getNationality().ifPresent(nationality -> sb.append(PREFIX_NATIONALITY)
+ .append(nationality.value).append(" "));
descriptor.getAddress().ifPresent(address -> sb.append(PREFIX_ADDRESS).append(address.value).append(" "));
- if (descriptor.getTags().isPresent()) {
- Set tags = descriptor.getTags().get();
- if (tags.isEmpty()) {
- sb.append(PREFIX_TAG);
- } else {
- tags.forEach(s -> sb.append(PREFIX_TAG).append(s.tagName).append(" "));
- }
- }
+ descriptor.getTag().ifPresent(tag -> sb.append(PREFIX_TAG)
+ .append(tag.getValue()[0])
+ .append("/")
+ .append(tag.getValue()[1])
+ .append("/")
+ .append(tag.getValue()[2]));
return sb.toString();
}
}
diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java
index fec76fb7129..bffe99f07cd 100644
--- a/src/test/java/seedu/address/testutil/TypicalPersons.java
+++ b/src/test/java/seedu/address/testutil/TypicalPersons.java
@@ -2,14 +2,26 @@
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DATE_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DATE_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DOB_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DOB_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GENDER_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_GENDER_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NATIONALITY_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NATIONALITY_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NOTE_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NOTE_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NRIC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NRIC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUMAN_RESOURCE;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_MARKETING;
import java.util.ArrayList;
import java.util.Arrays;
@@ -23,36 +35,145 @@
*/
public class TypicalPersons {
- public static final Person ALICE = new PersonBuilder().withName("Alice Pauline")
- .withAddress("123, Jurong West Ave 6, #08-111").withEmail("alice@example.com")
- .withPhone("94351253")
- .withTags("friends").build();
- public static final Person BENSON = new PersonBuilder().withName("Benson Meier")
- .withAddress("311, Clementi Ave 2, #02-25")
- .withEmail("johnd@example.com").withPhone("98765432")
- .withTags("owesMoney", "friends").build();
- public static final Person CARL = new PersonBuilder().withName("Carl Kurz").withPhone("95352563")
- .withEmail("heinz@example.com").withAddress("wall street").build();
- public static final Person DANIEL = new PersonBuilder().withName("Daniel Meier").withPhone("87652533")
- .withEmail("cornelia@example.com").withAddress("10th street").withTags("friends").build();
- public static final Person ELLE = new PersonBuilder().withName("Elle Meyer").withPhone("9482224")
- .withEmail("werner@example.com").withAddress("michegan ave").build();
- public static final Person FIONA = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427")
- .withEmail("lydia@example.com").withAddress("little tokyo").build();
- public static final Person GEORGE = new PersonBuilder().withName("George Best").withPhone("9482442")
- .withEmail("anna@example.com").withAddress("4th street").build();
+ public static final Person ALICE = new PersonBuilder()
+ .withName("Alice Pauline")
+ .withPhone("94351253").withNote("She likes aardvarks.")
+ .withEmail("alice@example.com")
+ .withNric("S9134567A")
+ .withGender("Female")
+ .withDob("01-Oct-1991")
+ .withDateOfJoining("15-Apr-2024")
+ .withNationality("Singaporean")
+ .withAddress("123, Jurong West Ave 6, #08-111/101010")
+ .withNote("In wonderland")
+ .withTags("Human Resources/Full-Time/HR Coordinator")
+ .build();
+
+ public static final Person BENSON = new PersonBuilder()
+ .withName("Benson Meier")
+ .withPhone("98765432")
+ .withEmail("johnd@example.com")
+ .withNric("T0134567B")
+ .withGender("Male")
+ .withDob("10-Mar-2001")
+ .withDateOfJoining("15-Apr-2024")
+ .withNationality("Singaporean")
+ .withAddress("311, Clementi Ave 2, #02-25/202020")
+ .withNote("He can't take beer!")
+ .withTags("Marketing/Part-Time/Marketing Specialist")
+ .build();
+
+ public static final Person CARL = new PersonBuilder()
+ .withName("Carl Kurz")
+ .withPhone("95352563")
+ .withEmail("heinz@example.com")
+ .withNric("T0234568C")
+ .withGender("Male")
+ .withDob("20-Aug-2002")
+ .withDateOfJoining("15-Apr-2024")
+ .withNationality("American")
+ .withAddress("wall street/010101")
+ .withNote("weathers")
+ .withTags("Information Technology/Full-Time/Software Engineer")
+ .build();
+
+ public static final Person DANIEL = new PersonBuilder()
+ .withName("Daniel Meier")
+ .withPhone("87652533")
+ .withEmail("cornelia@example.com")
+ .withNric("T0134569D")
+ .withGender("Male")
+ .withDob("19-Aug-2001")
+ .withDateOfJoining("15-Apr-2024")
+ .withNationality("American")
+ .withAddress("10th street/020202")
+ .withNote("cormier")
+ .withTags("Finance/Internship/Financial Analyst")
+ .build();
+
+ public static final Person ELLE = new PersonBuilder()
+ .withName("Elle Meyer")
+ .withPhone("94892224")
+ .withEmail("werner@example.com")
+ .withNric("T0234560E")
+ .withGender("Female")
+ .withDob("28-Dec-2002")
+ .withDateOfJoining("15-Apr-2024")
+ .withNationality("Indonesian")
+ .withAddress("michegan ave/030303")
+ .withNote("lee")
+ .withTags("Information Technology/Full-Time/Data Analyst")
+ .build();
+
+ public static final Person FIONA = new PersonBuilder()
+ .withName("Fiona Kunz")
+ .withPhone("94802427")
+ .withEmail("lydia@example.com")
+ .withNric("T0435560F")
+ .withGender("Female")
+ .withDob("30-Feb-2004")
+ .withDateOfJoining("01-Jan-2024")
+ .withNationality("Singaporean")
+ .withAddress("little tokyo/272727")
+ .withNote("and shrek")
+ .withTags("Information Technology/Part-Time/Data Analyst")
+ .build();
+
+ public static final Person GEORGE = new PersonBuilder()
+ .withName("George Best")
+ .withPhone("94829442")
+ .withEmail("anna@example.com")
+ .withNric("T0435569G")
+ .withGender("Male")
+ .withDob("27-Sep-2004")
+ .withDateOfJoining("01-Jan-2024")
+ .withNationality("American")
+ .withAddress("4th street/282828")
+ .withNote("Yeo.")
+ .withTags("Engineering/Part-Time/Electrical Engineer")
+ .build();
// Manually added
- public static final Person HOON = new PersonBuilder().withName("Hoon Meier").withPhone("8482424")
- .withEmail("stefan@example.com").withAddress("little india").build();
- public static final Person IDA = new PersonBuilder().withName("Ida Mueller").withPhone("8482131")
- .withEmail("hans@example.com").withAddress("chicago ave").build();
+ public static final Person HOON = new PersonBuilder()
+ .withName("Hoon Meier")
+ .withPhone("84824204")
+ .withEmail("stefan@example.com")
+ .withNric("T0135567H")
+ .withGender("Male")
+ .withDob("10-Dec-2001")
+ .withDateOfJoining("15-Dec-2024")
+ .withNationality("Singaporean")
+ .withAddress("little india/034343")
+ .withNote("Bee Hoon")
+ .withTags("Finance/Internship/Financial Analyst")
+ .build();
+
+ public static final Person IDA = new PersonBuilder()
+ .withName("Ida Mueller")
+ .withPhone("84821310")
+ .withEmail("hans@example.com")
+ .withNric("T0835561J")
+ .withGender("Female")
+ .withDob("01-Jan-2008")
+ .withDateOfJoining("15-Dec-2024")
+ .withNationality("Singaporean")
+ .withAddress("chicago ave/078901")
+ .withNote("nothing")
+ .withTags("Finance/Internship/Financial Analyst")
+ .build();
+
// Manually added - Person's details found in {@code CommandTestUtil}
public static final Person AMY = new PersonBuilder().withName(VALID_NAME_AMY).withPhone(VALID_PHONE_AMY)
- .withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY).withTags(VALID_TAG_FRIEND).build();
+ .withEmail(VALID_EMAIL_AMY).withNric(VALID_NRIC_AMY)
+ .withGender(VALID_GENDER_AMY).withDob(VALID_DOB_AMY)
+ .withDateOfJoining(VALID_DATE_AMY).withNationality(VALID_NATIONALITY_AMY)
+ .withAddress(VALID_ADDRESS_AMY).withNote(VALID_NOTE_AMY).withTags(VALID_TAG_HUMAN_RESOURCE).build();
public static final Person BOB = new PersonBuilder().withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND)
+ .withEmail(VALID_EMAIL_BOB).withNric(VALID_NRIC_BOB)
+ .withGender(VALID_GENDER_BOB).withDob(VALID_DOB_BOB)
+ .withDateOfJoining(VALID_DATE_BOB).withNationality(VALID_NATIONALITY_BOB)
+ .withAddress(VALID_ADDRESS_BOB).withNote(VALID_NOTE_BOB).withTags(VALID_TAG_MARKETING)
.build();
public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER