getReminderList() {
+ return model.getDisplayReminders();
+ }
+
+ @Override
+ public Path getClientHubFilePath() {
+ return model.getClientHubFilePath();
}
@Override
diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java
index ecd32c31b53..2758a697519 100644
--- a/src/main/java/seedu/address/logic/Messages.java
+++ b/src/main/java/seedu/address/logic/Messages.java
@@ -6,18 +6,38 @@
import seedu.address.logic.parser.Prefix;
import seedu.address.model.person.Person;
+import seedu.address.model.reminder.Reminder;
/**
* Container for user visible messages.
*/
public class Messages {
- public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
+ public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command! \n"
+ + "Please use the help command to see all available commands.";
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_DUPLICATE_FIELDS =
"Multiple values specified for the following single-valued field(s): ";
+ public static final String MESSAGE_PERSON_NOT_FOUND = "Client not found. \n"
+ + "Please double check the name of the client!";
+ public static final String MESSAGE_ADDRESS_NOT_FOUND = "Client not found. \n"
+ + "Please double check the address of the client!";
+ public static final String MESSAGE_PHONE_NOT_FOUND = "Client not found. \n"
+ + "Please double check the phone number of the client!";
+ public static final String MESSAGE_CLIENT_TYPE_NOT_FOUND = "Client not found. \n"
+ + "Please double check the client type(s) of the client!";
+ public static final String MESSAGE_VAGUE_DELETE = "Please be more specific in the name \n"
+ + "or use $ to indicate the end of an EXACT name";
+ public static final String MESSAGE_PERSON_LISTED_OVERVIEW_FOR_VIEW = "%1$d client found for viewing!";
+ public static final String MESSAGE_NO_PERSON_FOUND_FOR_VIEW =
+ "No clients found please use the list command to see all clients";
+ public static final String MESSAGE_INVALID_REMINDER_DISPLAYED_INDEX = "The reminder index provided is invalid";
+ public static final String MESSAGE_TARGET_DELETE_HAS_REMINDER = "The client has reminders, "
+ + "please delete them first";
+ public static final String MESSAGE_NO_CLIENT_TYPE =
+ "There should be at least one CLIENT_TYPE at all times";
+ public static final String MESSAGE_EDIT_PERSON_HAS_REMINDER = "The client has reminders, please delete them first!";
/**
* Returns an error message indicating the duplicate prefixes.
@@ -31,6 +51,25 @@ public static String getErrorMessageForDuplicatePrefixes(Prefix... duplicatePref
return MESSAGE_DUPLICATE_FIELDS + String.join(" ", duplicateFields);
}
+ /**
+ * Returns an overview message of the number of persons listed.
+ * The message will use the singular form "person" if the count is 1,
+ * and the plural form "persons" otherwise.
+ *
+ * @param count The number of persons listed.
+ * @return A formatted string with the count and the correct singular or plural term.
+ */
+ public static String getMessagePersonsListedOverview(int count) {
+ if (count == 0) {
+ return "0 client listed!, please use the list command to see all clients!";
+ }
+ if (count == 1) {
+ return "1 client listed!";
+ }
+ return String.format("%1$d clients listed!", count);
+ }
+
+
/**
* Formats the {@code person} for display to the user.
*/
@@ -43,9 +82,29 @@ public static String format(Person person) {
.append(person.getEmail())
.append("; Address: ")
.append(person.getAddress())
- .append("; Tags: ");
- person.getTags().forEach(builder::append);
+ .append("; Client Types: ");
+ person.getClientTypes().forEach(builder::append);
+ builder.append("; Description: ")
+ .append(person.getDescription());
return builder.toString();
}
+ /**
+ * Formats a {@code Reminder} object into a specific string representation.
+ *
+ * The formatted string includes the person associated with the reminder,
+ * the date and time of the reminder, and a description of the reminder, separated by semicolons.
+ *
+ * @param reminder The {@code Reminder} object to format.
+ * @return A formatted string containing the person's name, date and time, and description of the reminder.
+ */
+ public static String format(Reminder reminder) {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(reminder.getPersonName())
+ .append("; Date and Time: ")
+ .append(reminder.getFormattedDateTime())
+ .append("; Description: ")
+ .append(reminder.getDescription());
+ 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..f58bf158f6f 100644
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ b/src/main/java/seedu/address/logic/commands/AddCommand.java
@@ -2,10 +2,11 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENT_TYPE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
@@ -20,23 +21,31 @@ public class AddCommand extends Command {
public static final String COMMAND_WORD = "add";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. "
+ public static final String SHORT_COMMAND_WORD = "a";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a client to ClientHub.\n"
+ "Parameters: "
+ PREFIX_NAME + "NAME "
+ PREFIX_PHONE + "PHONE "
+ PREFIX_EMAIL + "EMAIL "
+ PREFIX_ADDRESS + "ADDRESS "
- + "[" + PREFIX_TAG + "TAG]...\n"
+ + PREFIX_DESCRIPTION + "DESCRIPTION "
+ + PREFIX_CLIENT_TYPE + "CLIENT_TYPE\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_CLIENT_TYPE + "Plan A "
+ + PREFIX_CLIENT_TYPE + "Plan B "
+ + PREFIX_DESCRIPTION + "Likes to eat a lot \n"
+ + "Additional Info:\n"
+ + "- Can add multiple c/ to add multiple CLIENT_TYPE\n";
- public static final String MESSAGE_SUCCESS = "New person added: %1$s";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book";
+ public static final String MESSAGE_SUCCESS = "New client added: %1$s";
+ public static final String MESSAGE_DUPLICATE_PERSON = "This name already exists in Client Hub. If the "
+ + "newly added client has the same name, please use parenthesis to add more information after the name "
+ + "to differentiate the clients.";
private final Person toAdd;
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java
index 9c86b1fa6e4..17ed429c3b0 100644
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ClearCommand.java
@@ -2,22 +2,22 @@
import static java.util.Objects.requireNonNull;
-import seedu.address.model.AddressBook;
+import seedu.address.model.ClientHub;
import seedu.address.model.Model;
/**
- * Clears the address book.
+ * Clears the client hub.
*/
public class ClearCommand extends Command {
public static final String COMMAND_WORD = "clear";
- public static final String MESSAGE_SUCCESS = "Address book has been cleared!";
+ public static final String MESSAGE_SUCCESS = "Client Hub has been cleared!";
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.setAddressBook(new AddressBook());
+ model.setClientHub(new ClientHub());
return new CommandResult(MESSAGE_SUCCESS);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/address/logic/commands/CommandResult.java
index 249b6072d0d..090c0c1472a 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/address/logic/commands/CommandResult.java
@@ -13,19 +13,24 @@ public class CommandResult {
private final String feedbackToUser;
+ /** View information should be shown to the user. */
+ private final boolean showView;
+
/** Help information should be shown to the user. */
private final boolean showHelp;
/** The application should exit. */
private final boolean exit;
+
/**
* Constructs a {@code CommandResult} with the specified fields.
*/
- public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
+ public CommandResult(String feedbackToUser, boolean showHelp, boolean showView, boolean exit) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
this.exit = exit;
+ this.showView = showView;
}
/**
@@ -33,7 +38,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 +53,10 @@ public boolean isExit() {
return exit;
}
+ public boolean isShowView() {
+ return showView;
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -62,12 +71,13 @@ public boolean equals(Object other) {
CommandResult otherCommandResult = (CommandResult) other;
return feedbackToUser.equals(otherCommandResult.feedbackToUser)
&& showHelp == otherCommandResult.showHelp
+ && showView == otherCommandResult.showView
&& exit == otherCommandResult.exit;
}
@Override
public int hashCode() {
- return Objects.hash(feedbackToUser, showHelp, exit);
+ return Objects.hash(feedbackToUser, showHelp, showView, exit);
}
@Override
@@ -75,6 +85,7 @@ public String toString() {
return new ToStringBuilder(this)
.add("feedbackToUser", feedbackToUser)
.add("showHelp", showHelp)
+ .add("showView", showView)
.add("exit", exit)
.toString();
}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
index 1135ac19b74..a92618150f6 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
@@ -1,14 +1,13 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-import java.util.List;
-
-import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
+import seedu.address.model.person.NameContainsKeywordsDeletePredicate;
import seedu.address.model.person.Person;
/**
@@ -17,31 +16,47 @@
public class DeleteCommand extends Command {
public static final String COMMAND_WORD = "delete";
+ public static final String SHORT_COMMAND_WORD = "d";
public static final String MESSAGE_USAGE = COMMAND_WORD
- + ": Deletes the person identified by the index number used in the displayed person list.\n"
- + "Parameters: INDEX (must be a positive integer)\n"
- + "Example: " + COMMAND_WORD + " 1";
+ + ": Deletes the client identified by their name in the displayed client list.\n"
+ + "Parameters: NAME (String & must be non-empty)\n"
+ + "Example: " + COMMAND_WORD + " John Doe "
+ + " or " + " "
+ + SHORT_COMMAND_WORD + " John Doe \n"
+ + "Additional Info: \n"
+ + "- To delete a client with a common name, please provide fullname or\n"
+ + "use $ to indicate the end of the name eg Jon snow$";
- public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
+ public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Client: %1$s";
- private final Index targetIndex;
+ private final NameContainsKeywordsDeletePredicate predicate;
- public DeleteCommand(Index targetIndex) {
- this.targetIndex = targetIndex;
+ public DeleteCommand(NameContainsKeywordsDeletePredicate predicate) {
+ this.predicate = predicate;
}
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
- if (targetIndex.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
- }
+ model.updateFilteredPersonList(predicate);
+ if (model.getDisplayPersons().isEmpty()) {
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ throw new CommandException(Messages.MESSAGE_PERSON_NOT_FOUND);
- Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
+ }
+ if (model.getDisplayPersons().size() > 1) {
+ model.updateFilteredPersonList(predicate);
+ throw new CommandException(Messages.MESSAGE_VAGUE_DELETE);
+ }
+ Person personToDelete = model.getDisplayPersons().get(0);
+ if (!personToDelete.getReminders().isEmpty()) {
+ model.updateFilteredPersonList(predicate);
+ throw new CommandException(Messages.MESSAGE_TARGET_DELETE_HAS_REMINDER);
+ }
model.deletePerson(personToDelete);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, Messages.format(personToDelete)));
}
@@ -57,13 +72,13 @@ public boolean equals(Object other) {
}
DeleteCommand otherDeleteCommand = (DeleteCommand) other;
- return targetIndex.equals(otherDeleteCommand.targetIndex);
+ return predicate.equals(otherDeleteCommand.predicate);
}
@Override
public String toString() {
return new ToStringBuilder(this)
- .add("targetIndex", targetIndex)
+ .add("predicate", predicate)
.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..105f53086b8 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/seedu/address/logic/commands/EditCommand.java
@@ -1,11 +1,13 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_EDIT_PERSON_HAS_REMINDER;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENT_TYPE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
import java.util.Collections;
@@ -21,12 +23,14 @@
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
+import seedu.address.model.clienttype.ClientType;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Description;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.reminder.Reminder;
/**
* Edits the details of an existing person in the address book.
@@ -35,22 +39,24 @@ public class EditCommand extends Command {
public static final String COMMAND_WORD = "edit";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified "
- + "by the index number used in the displayed person list. "
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the client identified "
+ + "by the index number used in the displayed client list. "
+ "Existing values will be overwritten by the input values.\n"
+ "Parameters: INDEX (must be a positive integer) "
+ "[" + PREFIX_NAME + "NAME] "
+ "[" + PREFIX_PHONE + "PHONE] "
+ "[" + PREFIX_EMAIL + "EMAIL] "
+ "[" + PREFIX_ADDRESS + "ADDRESS] "
- + "[" + PREFIX_TAG + "TAG]...\n"
+ + "[" + PREFIX_CLIENT_TYPE + "CLIENT_TYPE] "
+ + "[" + PREFIX_DESCRIPTION + "DESCRIPTION]\n"
+ "Example: " + COMMAND_WORD + " 1 "
+ PREFIX_PHONE + "91234567 "
+ PREFIX_EMAIL + "johndoe@example.com";
- public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s";
+ public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Client: %1$s";
public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book.";
+ public static final String MESSAGE_DUPLICATE_PERSON = "This name already exists in the client hub. If the "
+ + "newly added client has the same name, Please add (ADDITIONAL INFORMATION) to differentiate the names.";
private final Index index;
private final EditPersonDescriptor editPersonDescriptor;
@@ -70,7 +76,7 @@ public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
+ List lastShownList = model.getDisplayPersons();
if (index.getZeroBased() >= lastShownList.size()) {
throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
@@ -79,6 +85,10 @@ public CommandResult execute(Model model) throws CommandException {
Person personToEdit = lastShownList.get(index.getZeroBased());
Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
+ if (!personToEdit.getReminders().isEmpty() && editPersonDescriptor.isNameEdited()) {
+ throw new CommandException(MESSAGE_EDIT_PERSON_HAS_REMINDER);
+ }
+
if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
throw new CommandException(MESSAGE_DUPLICATE_PERSON);
}
@@ -99,9 +109,16 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript
Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone());
Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail());
Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
- Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
+ Set updatedClientTypes =
+ editPersonDescriptor.getClientTypes().orElse(personToEdit.getClientTypes());
+ Description updatedDescription = editPersonDescriptor.getDescription()
+ .orElse(personToEdit.getDescription());
+
+ // Edit Command doesn't allow editing of reminders
+ // Set updatedReminders = editPersonDescriptor.getReminders().orElse(personToEdit.getReminders());
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
+ return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress,
+ updatedClientTypes, updatedDescription, personToEdit.getReminders());
}
@Override
@@ -137,27 +154,34 @@ public static class EditPersonDescriptor {
private Phone phone;
private Email email;
private Address address;
- private Set tags;
+ private Set clientTypes;
+ private Description description;
+ private Set reminders;
public EditPersonDescriptor() {}
/**
* Copy constructor.
- * A defensive copy of {@code tags} is used internally.
+ * A defensive copy of {@code clientTypes} is used internally.
*/
public EditPersonDescriptor(EditPersonDescriptor toCopy) {
setName(toCopy.name);
setPhone(toCopy.phone);
setEmail(toCopy.email);
setAddress(toCopy.address);
- setTags(toCopy.tags);
+ setClientTypes(toCopy.clientTypes);
+ setDescription(toCopy.description);
}
/**
* 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, address, clientTypes, description);
+ }
+
+ public boolean isNameEdited() {
+ return this.name != null;
}
public void setName(Name name) {
@@ -188,25 +212,38 @@ public void setAddress(Address address) {
this.address = address;
}
+
public Optional getAddress() {
return Optional.ofNullable(address);
}
/**
- * Sets {@code tags} to this object's {@code tags}.
- * A defensive copy of {@code tags} is used internally.
+ * Sets {@code clientTypes} to this object's {@code clientTypes}.
+ * A defensive copy of {@code clientTypes} is used internally.
*/
- public void setTags(Set tags) {
- this.tags = (tags != null) ? new HashSet<>(tags) : null;
+ public void setClientTypes(Set clientTypes) {
+ this.clientTypes = (clientTypes != null) ? new HashSet<>(clientTypes) : null;
}
/**
- * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
+ * Returns an unmodifiable client types set, which throws {@code UnsupportedOperationException}
* if modification is attempted.
- * Returns {@code Optional#empty()} if {@code tags} is null.
+ * Returns {@code Optional#empty()} if {@code clientTypes} is null.
*/
- public Optional> getTags() {
- return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
+ public Optional> getClientTypes() {
+ return (clientTypes != null) ? Optional.of(Collections.unmodifiableSet(clientTypes)) : Optional.empty();
+ }
+
+ public void setDescription(Description description) {
+ this.description = description;
+ }
+
+ public Optional getDescription() {
+ return Optional.ofNullable(description);
+ }
+
+ public Optional> getReminders() {
+ return (reminders != null) ? Optional.of(Collections.unmodifiableSet(reminders)) : Optional.empty();
}
@Override
@@ -225,7 +262,9 @@ public boolean equals(Object other) {
&& Objects.equals(phone, otherEditPersonDescriptor.phone)
&& Objects.equals(email, otherEditPersonDescriptor.email)
&& Objects.equals(address, otherEditPersonDescriptor.address)
- && Objects.equals(tags, otherEditPersonDescriptor.tags);
+ && Objects.equals(clientTypes, otherEditPersonDescriptor.clientTypes)
+ && Objects.equals(description, otherEditPersonDescriptor.description)
+ && Objects.equals(reminders, otherEditPersonDescriptor.reminders);
}
@Override
@@ -235,7 +274,9 @@ public String toString() {
.add("phone", phone)
.add("email", email)
.add("address", address)
- .add("tags", tags)
+ .add("clientTypes", clientTypes)
+ .add("description", description)
+ .add("reminders", reminders)
.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..57a24b5cf68 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java
@@ -9,11 +9,11 @@ public class ExitCommand extends Command {
public static final String COMMAND_WORD = "exit";
- public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ...";
+ public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Client Hub as requested ...";
@Override
public CommandResult execute(Model model) {
- return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
+ return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, false, true);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/FindAddressCommand.java b/src/main/java/seedu/address/logic/commands/FindAddressCommand.java
new file mode 100644
index 00000000000..037609ab1d9
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindAddressCommand.java
@@ -0,0 +1,76 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.AddressContainsKeywordsPredicate;
+
+/**
+ * Finds and lists all persons in ClientHub whose name contains any of the argument keywords.
+ * Keyword matching is case insensitive.
+ */
+public class FindAddressCommand extends Command {
+
+ public static final String COMMAND_WORD = "fa";
+
+ public static final String MESSAGE_USAGE = FindCommand.COMMAND_WORD + " " + PREFIX_ADDRESS
+ + " or " + COMMAND_WORD
+ + ": Finds all clients whose address contain any of "
+ + "the specified ADDRESS and displays them as a list with index numbers.\n"
+ + "Parameters: ADDRESS\n"
+ + "Example:\n"
+ + "- " + COMMAND_WORD + " tampines\n"
+ + "- " + FindCommand.COMMAND_WORD + " " + PREFIX_ADDRESS + "tampines\n"
+ + "Additional Info: \n"
+ + "- ADDRESS is case-insensitive.\n"
+ + "- ADDRESS should not be empty.";
+
+ private final AddressContainsKeywordsPredicate predicate;
+
+ public FindAddressCommand(AddressContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+
+ // Check if there is anyone in the filtered list
+ if (model.getDisplayPersons().isEmpty()) {
+
+ // If noone found, show all persons (no change)
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ throw new CommandException(Messages.MESSAGE_ADDRESS_NOT_FOUND);
+ }
+ return new CommandResult(
+ Messages.getMessagePersonsListedOverview(model.getDisplayPersons().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FindAddressCommand)) {
+ return false;
+ }
+
+ FindAddressCommand otherFindAddressCommand = (FindAddressCommand) other;
+ return predicate.equals(otherFindAddressCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("predicate", predicate)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindClientTypeCommand.java b/src/main/java/seedu/address/logic/commands/FindClientTypeCommand.java
new file mode 100644
index 00000000000..3e1eb3e0449
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindClientTypeCommand.java
@@ -0,0 +1,80 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENT_TYPE;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.ClientTypeContainsKeywordsPredicate;
+
+/**
+ * Finds and lists all persons in address book whose client_type contains any of the argument keywords.
+ * Keyword matching is case insensitive.
+ */
+public class FindClientTypeCommand extends Command {
+
+ public static final String COMMAND_WORD = "fc";
+
+ public static final String MESSAGE_USAGE = FindCommand.COMMAND_WORD + " " + PREFIX_CLIENT_TYPE
+ + " or " + COMMAND_WORD
+ + ": Finds all clients whose names contain any of "
+ + "the specified CLIENT_TYPE and displays them as a list with index numbers.\n"
+ + "Parameters: CLIENT_TYPE [MORE_CLIENT_TYPES]...\n"
+ + "Examples: \n"
+ + COMMAND_WORD + " Investment Plan\n"
+ + COMMAND_WORD + " Investment Plan Healthcare\n"
+ + FindCommand.COMMAND_WORD + " " + PREFIX_CLIENT_TYPE + "Investment Plan\n"
+ + FindCommand.COMMAND_WORD + " " + PREFIX_CLIENT_TYPE + "Investment Plan Healthcare\n"
+ + "Additional Info: \n"
+ + "- CLIENT_TYPE is case-insensitive.\n"
+ + "- CLIENT_TYPE should not be empty.\n"
+ + "- Can specify multiple CLIENT_TYPE to have a more specific find.";
+
+
+ private final ClientTypeContainsKeywordsPredicate predicate;
+
+ public FindClientTypeCommand(ClientTypeContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+
+ // Check if there is anyone in the filtered list
+ if (model.getDisplayPersons().isEmpty()) {
+ // If noone found, show all persons (no change)
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ throw new CommandException(Messages.MESSAGE_CLIENT_TYPE_NOT_FOUND);
+ }
+ return new CommandResult(
+ Messages.getMessagePersonsListedOverview(model.getDisplayPersons().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FindClientTypeCommand)) {
+ return false;
+ }
+
+ FindClientTypeCommand otherFindCommand = (FindClientTypeCommand) other;
+ return predicate.equals(otherFindCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("predicate", predicate)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
index 72b9eddd3a7..b1724469193 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindCommand.java
@@ -8,17 +8,24 @@
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.
+ * Finds and lists all persons in ClientHub whose name contains any of the argument keywords.
+ * Keyword matching is case-insensitive.
*/
public class FindCommand extends Command {
public static final String COMMAND_WORD = "find";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
- + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
- + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
- + "Example: " + COMMAND_WORD + " alice bob charlie";
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds clients whose name, phone number, "
+ + "address or client type contain any of "
+ + "all specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ + "Parameters: n/NAME or p/PHONE_NUMBER, or a/ADDRESS or c/CLIENT_TYPE\n"
+ + "Examples:\n"
+ + "- " + COMMAND_WORD + " alice wong\n"
+ + "- " + COMMAND_WORD + " p/91234567\n"
+ + "- " + COMMAND_WORD + " a/123, Jurong West Ave 6\n"
+ + "- " + COMMAND_WORD + " c/Investment Plan 1\n"
+ + "Additional Info:\n"
+ + "- The command can only take in one prefix at any point of time. (find n/NAME a/Address is invalid)\n";
private final NameContainsKeywordsPredicate predicate;
@@ -31,7 +38,7 @@ public CommandResult execute(Model model) {
requireNonNull(model);
model.updateFilteredPersonList(predicate);
return new CommandResult(
- String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ Messages.getMessagePersonsListedOverview(model.getDisplayPersons().size()));
}
@Override
diff --git a/src/main/java/seedu/address/logic/commands/FindNameCommand.java b/src/main/java/seedu/address/logic/commands/FindNameCommand.java
new file mode 100644
index 00000000000..bbfeea81955
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindNameCommand.java
@@ -0,0 +1,78 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.NameContainsKeywordsPredicate;
+
+/**
+ * Finds and lists all persons in address book whose name contains any of the argument keywords.
+ * Keyword matching is case-insensitive.
+ */
+public class FindNameCommand extends Command {
+
+ public static final String COMMAND_WORD = "fn";
+
+ public static final String MESSAGE_USAGE = FindCommand.COMMAND_WORD + " " + PREFIX_NAME
+ + " or " + COMMAND_WORD
+ + ": Finds all clients whose names contain all of "
+ + "the prefix of the specified NAME and displays them as a list with index numbers.\n"
+ + "Parameters: NAME (String & must be non-empty)\n"
+ + "Example:\n"
+ + "- " + COMMAND_WORD + " Alice\n"
+ + "- " + FindCommand.COMMAND_WORD + " " + PREFIX_NAME + "Alice\n"
+ + "Additional Info: \n"
+ + "- NAME is case-insensitive.\n"
+ + "- It should contain letters, spaces, parenthesis or slashes only.\n"
+ + "- They cannot be empty or have only spaces.";
+
+ private final NameContainsKeywordsPredicate predicate;
+
+ public FindNameCommand(NameContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+
+ // Check if there is anyone in the filtered list
+ if (model.getDisplayPersons().isEmpty()) {
+
+ // If noone found, show all persons (no change)
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ throw new CommandException(Messages.MESSAGE_PERSON_NOT_FOUND);
+ }
+
+ return new CommandResult(
+ Messages.getMessagePersonsListedOverview(model.getDisplayPersons().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FindNameCommand)) {
+ return false;
+ }
+
+ FindNameCommand otherFindNameCommand = (FindNameCommand) other;
+ return predicate.equals(otherFindNameCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("predicate", predicate)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindPhoneCommand.java b/src/main/java/seedu/address/logic/commands/FindPhoneCommand.java
new file mode 100644
index 00000000000..4bdbcf8c05a
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindPhoneCommand.java
@@ -0,0 +1,76 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.PhoneBeginsWithKeywordPredicate;
+
+/**
+ * Finds and lists all persons in address book whose phone number begins with the argument keywords.
+ * Keyword matching has to be all numbers.
+ */
+public class FindPhoneCommand extends Command {
+
+ public static final String COMMAND_WORD = "fp";
+
+ public static final String MESSAGE_USAGE = FindCommand.COMMAND_WORD + " " + PREFIX_PHONE
+ + " or " + COMMAND_WORD
+ + ": Finds all clients whose phone number begins with "
+ + "the specified PHONE_NUMBER and displays them as a list with index numbers.\n"
+ + "Parameters: PHONE_NUMBER (Contains only 8 digits)\n"
+ + "Example:\n"
+ + "- " + COMMAND_WORD + " 91234567\n"
+ + "- " + FindCommand.COMMAND_WORD + " " + PREFIX_PHONE + "91234567\n"
+ + "Additional Info: \n"
+ + "- PHONE_NUMBER is a sequence of integers with no spacing.";
+
+
+ private final PhoneBeginsWithKeywordPredicate predicate;
+
+ public FindPhoneCommand(PhoneBeginsWithKeywordPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ model.updateFilteredPersonList(predicate);
+
+ // Check if there is anyone in the filtered list
+ if (model.getDisplayPersons().isEmpty()) {
+
+ // If noone found, show all persons (no change)
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ throw new CommandException(Messages.MESSAGE_PHONE_NOT_FOUND);
+ }
+ return new CommandResult(
+ Messages.getMessagePersonsListedOverview(model.getDisplayPersons().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof FindPhoneCommand)) {
+ return false;
+ }
+
+ FindPhoneCommand otherFindCommand = (FindPhoneCommand) other;
+ return predicate.equals(otherFindCommand.predicate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("predicate", predicate)
+ .toString();
+ }
+}
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..18a34475bda 100644
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ListCommand.java
@@ -1,7 +1,6 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
import seedu.address.model.Model;
@@ -11,14 +10,15 @@
public class ListCommand extends Command {
public static final String COMMAND_WORD = "list";
+ public static final String SHORT_COMMAND_WORD = "li";
- public static final String MESSAGE_SUCCESS = "Listed all persons";
+ public static final String MESSAGE_SUCCESS = "Listed all clients.";
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.updateUnfilteredList();
return new CommandResult(MESSAGE_SUCCESS);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/SortCommand.java b/src/main/java/seedu/address/logic/commands/SortCommand.java
new file mode 100644
index 00000000000..18731c61bdc
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/SortCommand.java
@@ -0,0 +1,65 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Comparator;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.NameComparator;
+import seedu.address.model.person.Person;
+
+/**
+ * Sorts the list of contacts in Client Hub.
+ */
+public class SortCommand extends Command {
+
+ public static final String COMMAND_WORD = "sort";
+ public static final String SHORT_COMMAND_WORD = "s";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + " CRITERIA"
+ + ": Sorts the list according to criteria given.\n"
+ + "Usage: sort";
+
+ public static final String MESSAGE_SUCCESS = "List sorted successfully!";
+
+ private final Comparator comparator;
+
+ /**
+ * Creates an SortCommand to sort the current list of contacts.
+ */
+ public SortCommand() {
+ this.comparator = new NameComparator();
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ model.updateSortedPersonList(comparator);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof SortCommand)) {
+ return false;
+ }
+
+ SortCommand otherSortCommand = (SortCommand) other;
+ return comparator.equals(otherSortCommand.comparator);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("comparator", comparator)
+ .toString();
+ }
+}
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..75655358a8b
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ViewCommand.java
@@ -0,0 +1,91 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.NameContainsKeywordsPredicate;
+
+
+/**
+ * Finds and creates a view popup of the specified client whose name contains any of the argument keywords.
+ * Keyword matching is case in-sensitive.
+ */
+public class ViewCommand extends Command {
+
+ public static final String COMMAND_WORD = "view";
+ public static final String SHORT_COMMAND_WORD = "v";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Creates a view of the specified client whose name"
+ + "contain any of "
+ + "the specified keywords (case-insensitive) and display them as a popup modal.\n"
+ + "Parameters: NAME\n"
+ + "Example: " + COMMAND_WORD + " " + "alice";
+
+ public static final String MORE_THAN_ONE_PERSON_VIEW_MESSAGE =
+ "\nMultiple clients found. Please specify the name of your client further.";
+
+ public static final String NO_PERSON_FOUND_VIEW_MESSAGE =
+ "Client not found for viewing. Please double check the name of your client!";
+
+ public static final String SHOWING_VIEW_MESSAGE = "Opened view window.";
+
+ private final NameContainsKeywordsPredicate predicate;
+
+ public ViewCommand(NameContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ // In the list, it will show the person that is viewed
+ model.updateFilteredPersonList(predicate);
+
+ // Check if there is anyone in the filtered list
+ if (model.getDisplayPersons().isEmpty()) {
+
+ // If noone found, show all persons (no change)
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ throw new CommandException(NO_PERSON_FOUND_VIEW_MESSAGE);
+ }
+
+ // Check if there are duplicates
+ if (model.getDisplayPersons().size() > 1) {
+ throw new CommandException(
+ String.format(Messages.MESSAGE_PERSON_LISTED_OVERVIEW_FOR_VIEW,
+ model.getDisplayPersonsListSize())
+ + MORE_THAN_ONE_PERSON_VIEW_MESSAGE
+ );
+ }
+ return new CommandResult(
+ String.format(Messages.MESSAGE_PERSON_LISTED_OVERVIEW_FOR_VIEW, model.getDisplayPersons().size()),
+ false, true, false);
+ }
+
+ @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/commands/reminder/AddReminderCommand.java b/src/main/java/seedu/address/logic/commands/reminder/AddReminderCommand.java
new file mode 100644
index 00000000000..99c19b45158
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/reminder/AddReminderCommand.java
@@ -0,0 +1,126 @@
+package seedu.address.logic.commands.reminder;
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_TIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+
+import java.util.List;
+
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.Person;
+import seedu.address.model.reminder.Reminder;
+
+/**
+ * Adds a reminder to the address book.
+ */
+public class AddReminderCommand extends Command {
+ public static final String COMMAND_WORD = "radd"; // reminder add
+ public static final String COMMAND_WORD_SHORT = "ra"; // reminder add
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + " or " + COMMAND_WORD_SHORT
+ + ": Adds a reminder to Client hub.\n"
+ + "Parameters: "
+ + PREFIX_NAME + "NAME, "
+ + PREFIX_DATE_TIME + "DATE_AND_TIME, "
+ + PREFIX_DESCRIPTION + "DESCRIPTION\n"
+ + "Examples:\n"
+ + "- " + COMMAND_WORD + " " + PREFIX_NAME + "John " + PREFIX_DATE_TIME + "2021-12-31 23:59 "
+ + PREFIX_DESCRIPTION + "New Year's Eve\n"
+ + "- " + COMMAND_WORD_SHORT + " " + PREFIX_NAME + "John " + PREFIX_DATE_TIME + "2021-12-31 23:59 "
+ + PREFIX_DESCRIPTION + "New Year's Eve\n";
+
+
+ public static final String MESSAGE_SUCCESS = "New reminder added: %1$s";
+ public static final String MESSAGE_NONEXISTENT_PERSON = "This client doesn't exist in the Client Hub.";
+ public static final String MESSAGE_MORE_THAN_ONE_PERSON = "There is more than one client with this name in "
+ + "client hub. Please use a more specific name instead.";
+
+ private final Reminder toAdd;
+
+ /**
+ * Constructs an {@code AddReminderCommand} with the specified {@code Reminder}.
+ *
+ * This command initializes an instance that will add the given reminder.
+ * The reminder must not be null.
+ *
+ * @param reminder The {@code Reminder} to be added.
+ * @throws NullPointerException if {@code reminder} is null.
+ */
+ public AddReminderCommand(Reminder reminder) {
+ requireNonNull(reminder);
+ toAdd = reminder;
+ }
+
+ /**
+ * Executes the command to add a reminder to the model.
+ *
+ * @param model The {@code Model} which the command should operate on.
+ * @return A {@code CommandResult} indicating the outcome of the command execution.
+ * @throws CommandException If there is an issue during command execution.
+ */
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ // Parse input using the NameContainsKeywordsPredicate
+ String[] nameKeywords = toAdd.getPersonName().split("\\s+");
+ NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(List.of(nameKeywords));
+ List matchingPersons = model.getClientHub().getPersonList().filtered(predicate);
+
+ // Check if there is exactly one match
+ if (matchingPersons.size() == 1) {
+ Person person = matchingPersons.get(0);
+
+ // Creates a new reminder with the full name of the person
+ Reminder reminderWithFullName = toAdd.getReminderWithFullName(person.getName().fullName);
+ person.addReminder(reminderWithFullName);
+ model.updateFilteredPersonList(Model.PREDICATE_SHOW_ALL_PERSONS);
+
+ return new CommandResult(String.format(MESSAGE_SUCCESS, Messages.format(reminderWithFullName)));
+ } else if (matchingPersons.isEmpty()) {
+ throw new CommandException(MESSAGE_NONEXISTENT_PERSON);
+ } else {
+ model.updateFilteredPersonList(predicate);
+ throw new CommandException(MESSAGE_MORE_THAN_ONE_PERSON);
+ }
+ }
+
+ /**
+ * Checks if this {@code AddReminderCommand} is equal to another object.
+ *
+ * @param other The other object to compare to.
+ * @return {@code true} if the other object is an {@code AddReminderCommand}, otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object other) {
+ // Check if same object
+ if (other == this) {
+ return true;
+ }
+
+ // Check if instance of AddReminderCommand and compare reminders
+ if (other instanceof AddReminderCommand) {
+ AddReminderCommand otherCommand = (AddReminderCommand) other;
+ return toAdd.equals(otherCommand.toAdd);
+ }
+
+ // If neither of the above, return false
+ return false;
+ }
+
+ /**
+ * Returns a string representation of the {@code AddReminderCommand}.
+ *
+ * @return A string representation of the command.
+ */
+ @Override
+ public String toString() {
+ return "AddReminderCommand {" + "toAdd=" + toAdd + '}';
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/reminder/DeleteReminderCommand.java b/src/main/java/seedu/address/logic/commands/reminder/DeleteReminderCommand.java
new file mode 100644
index 00000000000..10b1828accd
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/reminder/DeleteReminderCommand.java
@@ -0,0 +1,109 @@
+package seedu.address.logic.commands.reminder;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import javafx.collections.ObservableList;
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.NameContainsKeywordsDeletePredicate;
+import seedu.address.model.person.Person;
+import seedu.address.model.reminder.Reminder;
+
+/**
+ * Deletes a reminder identified using its displayed index from the reminder list.
+ */
+public class DeleteReminderCommand extends Command {
+
+ public static final String COMMAND_WORD = "rdelete";
+ public static final String COMMAND_WORD_SHORT = "rd";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + " or " + COMMAND_WORD_SHORT
+ + ": Deletes the reminder "
+ + "identified by the index number used in the displayed reminder list.\n"
+ + "Parameters: INDEX (must be a positive integer)\n"
+ + "Example:\n"
+ + "- " + COMMAND_WORD + " 1\n"
+ + "- " + COMMAND_WORD_SHORT + " 1";
+
+ public static final String MESSAGE_DELETE_REMINDER_SUCCESS = "Deleted Reminder: %1$s";
+
+ public static final String MESSAGE_INVALID_REMINDER_DISPLAYED_INDEX = "The reminder index provided is invalid";
+
+ private final Index targetIndex;
+
+ /**
+ * Constructs a {@code DeleteReminderCommand} with the specified target index.
+ *
+ * @param targetIndex The index of the reminder to be deleted.
+ */
+ public DeleteReminderCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ /**
+ * Executes the command to delete the reminder from the model.
+ *
+ * @param model The {@code Model} which the command should operate on.
+ * @return A {@code CommandResult} indicating the result of the command execution.
+ * @throws CommandException If the specified index is invalid (out of bounds).
+ */
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ List lastShownList = model.getDisplayReminders();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size() || targetIndex.getZeroBased() < 0) {
+ throw new CommandException(MESSAGE_INVALID_REMINDER_DISPLAYED_INDEX);
+ }
+
+ Reminder reminderToDelete = lastShownList.get(targetIndex.getZeroBased());
+ model.deleteReminder(reminderToDelete);
+
+ // Parse input using the NameContainsKeywordsPredicate
+ String fullName = reminderToDelete.getPersonName() + "$";
+ String[] nameKeywords = fullName.split("\\s+");
+ NameContainsKeywordsDeletePredicate predicate = new NameContainsKeywordsDeletePredicate(
+ List.of(nameKeywords));
+ ObservableList persons = model.getClientHub().getPersonList();
+ List matchingPersons = persons.filtered(predicate);
+
+ // Check if there is exactly one match
+ if (matchingPersons.size() == 1) {
+ Person person = matchingPersons.get(0);
+ person.deleteReminder(reminderToDelete);
+ return new CommandResult(String.format(MESSAGE_DELETE_REMINDER_SUCCESS, Messages.format(reminderToDelete)));
+ } else {
+ throw new CommandException("More than one person with the specified name found. Please be more specific.");
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ // instanceof handles nulls
+ if (!(other instanceof DeleteReminderCommand)) {
+ return false;
+ }
+
+ DeleteReminderCommand otherDeleteCommand = (DeleteReminderCommand) other;
+ return targetIndex.equals(otherDeleteCommand.targetIndex);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("targetIndex", targetIndex)
+ .toString();
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/commands/reminder/EditReminderCommand.java b/src/main/java/seedu/address/logic/commands/reminder/EditReminderCommand.java
new file mode 100644
index 00000000000..9e30124e6f7
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/reminder/EditReminderCommand.java
@@ -0,0 +1,192 @@
+package seedu.address.logic.commands.reminder;
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_TIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import javafx.collections.ObservableList;
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.util.CollectionUtil;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.CommandResult;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.NameContainsKeywordsDeletePredicate;
+import seedu.address.model.person.Person;
+import seedu.address.model.reminder.Reminder;
+import seedu.address.model.reminder.ReminderDescription;
+
+/**
+ * Edits a reminder in the address book.
+ */
+public class EditReminderCommand extends Command {
+ public static final String COMMAND_WORD = "redit"; // reminder edit
+ public static final String COMMAND_WORD_SHORT = "re"; // reminder edit
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + " or " + COMMAND_WORD_SHORT
+ + ": Edits a reminder in Client Hub identified "
+ + "by the index number displayed in the reminder list.\n"
+ + "Parameters: INDEX "
+ + "[" + PREFIX_DATE_TIME + "DATE_TIME] "
+ + "[" + PREFIX_DESCRIPTION + "DESCRIPTION]\n"
+ + "Examples:\n"
+ + COMMAND_WORD + " 1 " + PREFIX_DATE_TIME + "2022-01-01 00:00 "
+ + PREFIX_DESCRIPTION + "New Year's\n"
+ + COMMAND_WORD_SHORT + " 1 " + PREFIX_DATE_TIME + "2022-01-01 00:00 "
+ + PREFIX_DESCRIPTION + "New Year's\n"
+ + "Additional Info:\n"
+ + "- " + "INDEX must be a positive integer.\n"
+ + "- " + "Existing values will be overwritten by the input values.";
+
+ public static final String MESSAGE_EDIT_REMINDER_SUCCESS = "Edited reminder %1$s";
+ public static final String MESSAGE_REMINDER_NOT_EDITED = "At least one field must be edited";
+
+ private final Index index;
+ private final EditReminderFields editReminderFields;
+
+ /**
+ * @param index of the reminder in the reminder list to edit
+ * @param editReminderFields details of the edited reminder
+ */
+ public EditReminderCommand(Index index, EditReminderFields editReminderFields) {
+ requireNonNull(index);
+ requireNonNull(editReminderFields);
+
+ this.index = index;
+ this.editReminderFields = new EditReminderFields(editReminderFields);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getDisplayReminders();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_REMINDER_DISPLAYED_INDEX);
+ }
+
+ Reminder reminderToEdit = lastShownList.get(index.getZeroBased());
+ Reminder editedReminder = createEditedReminder(reminderToEdit, editReminderFields);
+
+ if (reminderToEdit.isSameReminder(editedReminder)
+ || !editReminderFields.isAnyFieldEdited()) {
+ throw new CommandException(MESSAGE_REMINDER_NOT_EDITED);
+ }
+
+ // Parse input using the NameContainsKeywordsPredicate
+ String fullName = reminderToEdit.getPersonName() + "$";
+ String[] nameKeywords = fullName.split("\\s+");
+ NameContainsKeywordsDeletePredicate predicate = new NameContainsKeywordsDeletePredicate(
+ List.of(nameKeywords));
+ ObservableList persons = model.getClientHub().getPersonList();
+ List matchingPersons = persons.filtered(predicate);
+
+ // Check if there is exactly one match
+ if (matchingPersons.size() == 1) {
+ Person person = matchingPersons.get(0);
+ person.deleteReminder(reminderToEdit);
+ person.addReminder(editedReminder);
+ model.setReminder(reminderToEdit, editedReminder);
+ model.updateFilteredReminderList();
+ return new CommandResult(String.format(MESSAGE_EDIT_REMINDER_SUCCESS, Messages.format(editedReminder)));
+ } else {
+ throw new CommandException("More than one person with the specified name found. Please be more specific.");
+ }
+ }
+
+ /**
+ * Creates and returns an edited a {@code Reminder} with the details of {@code reminderToEdit}
+ * edited with the details of {@code editReminderFields}.
+ */
+ public static Reminder createEditedReminder(Reminder reminderToEdit, EditReminderFields editReminderFields) {
+ assert reminderToEdit != null;
+
+ // EditReminder does not allow editing of personName
+ String personName = reminderToEdit.getPersonName();
+ LocalDateTime updatedDateTime = editReminderFields.getDateTime().orElse(reminderToEdit.getDateTime());
+ ReminderDescription updatedDescription = editReminderFields.getDescription()
+ .orElse(reminderToEdit.getDescription());
+
+ return new Reminder(personName, updatedDateTime, updatedDescription);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || other instanceof EditReminderCommand; // instanceof handles nulls
+ }
+
+ @Override
+ public String toString() {
+ return "EditReminderCommand";
+ }
+
+ /**
+ * Stores the details to edit the reminder with. Each non-empty field value will replace the
+ * corresponding field value of the reminder.
+ */
+ public static class EditReminderFields {
+ private LocalDateTime dateTime;
+ private ReminderDescription description;
+
+ /**
+ * Default constructor for {@code EditReminderFields}.
+ * Initializes an instance with no specified fields.
+ */
+ public EditReminderFields() {}
+
+ /**
+ * Copy constructor for {@code EditReminderFields}.
+ * Creates a new instance by copying the fields from the specified {@code EditReminderFields} instance.
+ *
+ * @param toCopy The {@code EditReminderFields} instance to copy from. Must not be {@code null}.
+ */
+ public EditReminderFields(EditReminderFields toCopy) {
+ setDateTime(toCopy.dateTime);
+ setDescription(toCopy.description);
+ }
+
+ /**
+ * @return true if any field is edited
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(dateTime, description);
+ }
+
+ public void setDateTime(LocalDateTime dateTime) {
+ this.dateTime = dateTime;
+ }
+
+ public Optional getDateTime() {
+ return Optional.ofNullable(dateTime);
+ }
+ public void setDescription(ReminderDescription description) {
+ this.description = description;
+ }
+
+ public Optional getDescription() {
+ return Optional.ofNullable(description);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this || other instanceof EditReminderFields) {
+ return true;
+ }
+
+ EditReminderFields otherEditReminderFields = (EditReminderFields) other;
+ return Objects.equals(dateTime, otherEditReminderFields.dateTime)
+ && Objects.equals(description, otherEditReminderFields.description);
+ }
+
+ @Override
+ public String toString() {
+ return "EditReminderFields";
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
index 4ff1a97ed77..f2712f17288 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
@@ -2,28 +2,47 @@
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_CLIENT_TYPE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import java.util.Collections;
+import java.util.HashMap;
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.clienttype.ClientType;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Description;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.reminder.Reminder;
/**
* Parses input arguments and creates a new AddCommand object
*/
public class AddCommandParser implements Parser {
+ private static final String MESSAGE_MISSING_FIELD = "The following field for add command is missing: %s";
+ private static final String MESSAGE_MULTIPLE_MISSING_FIELDS =
+ "The following fields for add command are missing: %s";
+
+ // Map to store prefix to field description mapping
+ private static final HashMap FIELD_DESCRIPTIONS = new HashMap<>();
+ static {
+ FIELD_DESCRIPTIONS.put(PREFIX_NAME, "NAME");
+ FIELD_DESCRIPTIONS.put(PREFIX_PHONE, "PHONE");
+ FIELD_DESCRIPTIONS.put(PREFIX_EMAIL, "EMAIL");
+ FIELD_DESCRIPTIONS.put(PREFIX_ADDRESS, "ADDRESS");
+ FIELD_DESCRIPTIONS.put(PREFIX_CLIENT_TYPE, "CLIENT_TYPE");
+ FIELD_DESCRIPTIONS.put(PREFIX_DESCRIPTION, "DESCRIPTION");
+ }
+
/**
* Parses the given {@code String} of arguments in the context of the AddCommand
* and returns an AddCommand object for execution.
@@ -31,21 +50,28 @@ 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_ADDRESS,
+ PREFIX_CLIENT_TYPE, PREFIX_DESCRIPTION);
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
- || !argMultimap.getPreamble().isEmpty()) {
+ // Check for missing fields
+ arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE,
+ PREFIX_EMAIL, PREFIX_CLIENT_TYPE, PREFIX_DESCRIPTION);
+
+ // Only check for preamble if there are no missing fields
+ 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_ADDRESS,
+ PREFIX_DESCRIPTION);
Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
- Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
-
- Person person = new Person(name, phone, email, address, tagList);
+ Set clientTypeList = ParserUtil.parseClientTypes(argMultimap.getAllValues(PREFIX_CLIENT_TYPE));
+ Description description = ParserUtil.parseDescription(argMultimap.getValue(PREFIX_DESCRIPTION).get());
+ Set reminders = Collections.emptySet();
+ Person person = new Person(name, phone, email, address, clientTypeList, description, reminders);
return new AddCommand(person);
}
@@ -54,8 +80,32 @@ public AddCommand parse(String args) throws ParseException {
* Returns true if none of the prefixes contains empty {@code Optional} values in the given
* {@code ArgumentMultimap}.
*/
- private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
- return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ private static void arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes)
+ throws ParseException {
+ //return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+
+ StringBuilder missingFields = new StringBuilder();
+
+ for (Prefix prefix : prefixes) {
+ if (prefix == PREFIX_CLIENT_TYPE) {
+ if (argumentMultimap.getAllValues(prefix).isEmpty()) {
+ missingFields.append(String.format("%s%s ",
+ prefix.getPrefix(), FIELD_DESCRIPTIONS.get(prefix)));
+ }
+ } else if (!argumentMultimap.getValue(prefix).isPresent()) {
+ missingFields.append(String.format("%s%s ",
+ prefix.getPrefix(), FIELD_DESCRIPTIONS.get(prefix)));
+ }
+ }
+
+ // If any fields are missing, throw exception with specific message
+ if (missingFields.length() > 0) {
+ String missingFieldsStr = missingFields.toString().trim();
+ String message = missingFieldsStr.contains(" ")
+ ? String.format(MESSAGE_MULTIPLE_MISSING_FIELDS, missingFieldsStr)
+ : String.format(MESSAGE_MISSING_FIELD, missingFieldsStr);
+ throw new ParseException(message);
+ }
}
}
diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java
index 75b1a9bf119..48540da60d5 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java
@@ -10,6 +10,7 @@ public class CliSyntax {
public static final Prefix PREFIX_PHONE = new Prefix("p/");
public static final Prefix PREFIX_EMAIL = new Prefix("e/");
public static final Prefix PREFIX_ADDRESS = new Prefix("a/");
- public static final Prefix PREFIX_TAG = new Prefix("t/");
-
+ public static final Prefix PREFIX_CLIENT_TYPE = new Prefix("c/");
+ public static final Prefix PREFIX_DESCRIPTION = new Prefix("d/");
+ public static final Prefix PREFIX_DATE_TIME = new Prefix("dt/");
}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/ClientHubParser.java
similarity index 56%
rename from src/main/java/seedu/address/logic/parser/AddressBookParser.java
rename to src/main/java/seedu/address/logic/parser/ClientHubParser.java
index 3149ee07e0b..45dc2e378c3 100644
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/address/logic/parser/ClientHubParser.java
@@ -14,21 +14,33 @@
import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.ExitCommand;
+import seedu.address.logic.commands.FindAddressCommand;
+import seedu.address.logic.commands.FindClientTypeCommand;
import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.FindNameCommand;
+import seedu.address.logic.commands.FindPhoneCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.SortCommand;
+import seedu.address.logic.commands.ViewCommand;
+import seedu.address.logic.commands.reminder.AddReminderCommand;
+import seedu.address.logic.commands.reminder.DeleteReminderCommand;
+import seedu.address.logic.commands.reminder.EditReminderCommand;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.logic.parser.reminder.AddReminderCommandParser;
+import seedu.address.logic.parser.reminder.DeleteReminderCommandParser;
+import seedu.address.logic.parser.reminder.EditReminderCommandParser;
/**
* Parses user input.
*/
-public class AddressBookParser {
+public class ClientHubParser {
/**
* Used for initial separation of command word and args.
*/
private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)");
- private static final Logger logger = LogsCenter.getLogger(AddressBookParser.class);
+ private static final Logger logger = LogsCenter.getLogger(ClientHubParser.class);
/**
* Parses user input into command for execution.
@@ -53,30 +65,57 @@ public Command parseCommand(String userInput) throws ParseException {
switch (commandWord) {
- case AddCommand.COMMAND_WORD:
+ case AddCommand.COMMAND_WORD, AddCommand.SHORT_COMMAND_WORD:
return new AddCommandParser().parse(arguments);
case EditCommand.COMMAND_WORD:
return new EditCommandParser().parse(arguments);
- case DeleteCommand.COMMAND_WORD:
+ case DeleteCommand.COMMAND_WORD, DeleteCommand.SHORT_COMMAND_WORD:
return new DeleteCommandParser().parse(arguments);
- case ClearCommand.COMMAND_WORD:
- return new ClearCommand();
-
case FindCommand.COMMAND_WORD:
return new FindCommandParser().parse(arguments);
- case ListCommand.COMMAND_WORD:
+ case FindPhoneCommand.COMMAND_WORD:
+ return new FindPhoneCommandParser().parse(arguments);
+
+ case FindClientTypeCommand.COMMAND_WORD:
+ return new FindClientTypeCommandParser().parse(arguments);
+
+ case FindNameCommand.COMMAND_WORD:
+ return new FindNameCommandParser().parse(arguments);
+
+ case FindAddressCommand.COMMAND_WORD:
+ return new FindAddressCommandParser().parse(arguments);
+
+ case ListCommand.COMMAND_WORD, ListCommand.SHORT_COMMAND_WORD:
return new ListCommand();
+ case SortCommand.COMMAND_WORD, SortCommand.SHORT_COMMAND_WORD:
+ return new SortCommand();
+
+ case ViewCommand.COMMAND_WORD, ViewCommand.SHORT_COMMAND_WORD:
+ return new ViewCommandParser().parse(arguments);
+
+ case ClearCommand.COMMAND_WORD:
+ return new ClearCommand();
+
case ExitCommand.COMMAND_WORD:
return new ExitCommand();
case HelpCommand.COMMAND_WORD:
return new HelpCommand();
+ case DeleteReminderCommand.COMMAND_WORD, DeleteReminderCommand.COMMAND_WORD_SHORT:
+ return new DeleteReminderCommandParser().parse(arguments);
+
+ case AddReminderCommand.COMMAND_WORD, AddReminderCommand.COMMAND_WORD_SHORT:
+ return new AddReminderCommandParser().parse(arguments);
+
+ case EditReminderCommand.COMMAND_WORD, EditReminderCommand.COMMAND_WORD_SHORT:
+ return new EditReminderCommandParser().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/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
index 3527fe76a3e..95f007e43c2 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
@@ -2,9 +2,12 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import seedu.address.commons.core.index.Index;
+import java.util.Arrays;
+
import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Name;
+import seedu.address.model.person.NameContainsKeywordsDeletePredicate;
/**
* Parses input arguments and creates a new DeleteCommand object
@@ -17,13 +20,19 @@ public class DeleteCommandParser implements Parser {
* @throws ParseException if the user input does not conform the expected format
*/
public DeleteCommand parse(String args) throws ParseException {
- try {
- Index index = ParserUtil.parseIndex(args);
- return new DeleteCommand(index);
- } catch (ParseException pe) {
+ String personNames = args.trim();
+ if (!Name.isValidName(personNames) && !personNames.endsWith("$")) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteCommand.MESSAGE_USAGE));
+ }
+ if (personNames.isEmpty()) {
throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
}
+
+ String[] nameKeywords = personNames.split("\\s+");
+ return new DeleteCommand(new NameContainsKeywordsDeletePredicate(Arrays.asList(nameKeywords)));
}
+
}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
index 46b3309a78b..9a8bccf94b2 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
@@ -3,21 +3,22 @@
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_CLIENT_TYPE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import java.util.Collection;
-import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
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.clienttype.ClientType;
/**
* Parses input arguments and creates a new EditCommand object
@@ -32,7 +33,8 @@ 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_ADDRESS,
+ PREFIX_CLIENT_TYPE, PREFIX_DESCRIPTION);
Index index;
@@ -42,7 +44,8 @@ public EditCommand parse(String args) throws ParseException {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_DESCRIPTION);
EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
@@ -58,7 +61,13 @@ public EditCommand parse(String args) throws ParseException {
if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
}
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
+ parseClientTypesForEdit(argMultimap.getAllValues(PREFIX_CLIENT_TYPE))
+ .ifPresent(editPersonDescriptor::setClientTypes);
+
+ if (argMultimap.getValue(PREFIX_DESCRIPTION).isPresent()) {
+ editPersonDescriptor.setDescription(ParserUtil.parseDescription(argMultimap
+ .getValue(PREFIX_DESCRIPTION).get()));
+ }
if (!editPersonDescriptor.isAnyFieldEdited()) {
throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
@@ -68,18 +77,22 @@ public EditCommand parse(String args) throws ParseException {
}
/**
- * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty.
- * If {@code tags} contain only one element which is an empty string, it will be parsed into a
- * {@code Set} containing zero tags.
+ * Parses {@code Collection clientTypes} into a {@code Set}
+ * if {@code clientTypes} is non-empty.
+ * If {@code clientTypes} contain only one element which is an empty string, it will be parsed into a
+ * {@code Set} containing zero clientTypes.
*/
- private Optional> parseTagsForEdit(Collection tags) throws ParseException {
- assert tags != null;
+ private Optional> parseClientTypesForEdit(Collection clientTypes) throws ParseException {
+ assert clientTypes != null;
- if (tags.isEmpty()) {
+ if (clientTypes.isEmpty()) {
return Optional.empty();
}
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
+ if (clientTypes.size() == 1 && clientTypes.contains("")) {
+ throw new ParseException(Messages.MESSAGE_NO_CLIENT_TYPE);
+ } else {
+ return Optional.of(ParserUtil.parseClientTypes(clientTypes));
+ }
}
}
diff --git a/src/main/java/seedu/address/logic/parser/FindAddressCommandParser.java b/src/main/java/seedu/address/logic/parser/FindAddressCommandParser.java
new file mode 100644
index 00000000000..e81bb3b0692
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindAddressCommandParser.java
@@ -0,0 +1,28 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.logic.commands.FindAddressCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.AddressContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FindAddressCommand object
+ */
+public class FindAddressCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindAddressCommand
+ * and returns a FindAddressCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindAddressCommand parse(String args) throws ParseException {
+ String addressKeywords = args.trim();
+ if (addressKeywords.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindAddressCommand.MESSAGE_USAGE));
+ }
+
+ return new FindAddressCommand(new AddressContainsKeywordsPredicate(addressKeywords));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindClientTypeCommandParser.java b/src/main/java/seedu/address/logic/parser/FindClientTypeCommandParser.java
new file mode 100644
index 00000000000..885d2e12a80
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindClientTypeCommandParser.java
@@ -0,0 +1,39 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Arrays;
+
+import seedu.address.logic.commands.FindClientTypeCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.ClientTypeContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FindClientTypeCommand object
+ */
+public class FindClientTypeCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindClientTypeCommand
+ * and returns a FindClientTypeCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindClientTypeCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindClientTypeCommand.MESSAGE_USAGE));
+ }
+
+ // Check for special characters - only allow alphanumeric and whitespace
+ if (!trimmedArgs.matches("^[a-zA-Z0-9\\s]+$")) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindClientTypeCommand.MESSAGE_USAGE));
+ }
+
+ String[] clientTypeKeywords = trimmedArgs.split("\\s+");
+
+ return new FindClientTypeCommand(new ClientTypeContainsKeywordsPredicate(Arrays.asList(clientTypeKeywords)));
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
index 2867bde857b..5723ba2c91d 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
@@ -3,31 +3,106 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import java.util.Arrays;
+import java.util.List;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.FindAddressCommand;
+import seedu.address.logic.commands.FindClientTypeCommand;
+//import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.FindNameCommand;
+import seedu.address.logic.commands.FindPhoneCommand;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.AddressContainsKeywordsPredicate;
+import seedu.address.model.person.ClientTypeContainsKeywordsPredicate;
import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.PhoneBeginsWithKeywordPredicate;
/**
- * Parses input arguments and creates a new FindCommand object
+ * Parses input arguments and creates a new FindCommand object based on the prefix provided.
+ *
+ * If the input starts with the prefix:
+ * - "n/" (name): a {@code FindNameCommand} will be returned, which finds persons whose names contain
+ * the specified keywords.
+ * - "p/" (phone): a {@code FindPhoneCommand} will be returned, which finds persons whose phone numbers begin
+ * with the specified keyword.
+ * - "a/" (address): a {@code FindAddressCommand} will be returned, which finds persons whose addresses
+ * contain the specified keywords.
+ * - "c/" (client type): a {@code FindClientTypeCommand} will be returned, which finds persons
+ * based on their client type.
+ *
+ * The matching for name, address, and client type is case-insensitive, and the keywords can be separated by whitespace.
+ * However, the phone number is treated as a single string.
+ *
+ * The parser checks if the input is correctly formatted and throws a {@code ParseException} if any input is invalid.
*/
-public class FindCommandParser implements Parser {
+public class FindCommandParser implements Parser {
+
+ private static final String PREFIX_NAME = "n/";
+ private static final String PREFIX_PHONE = "p/";
+ private static final String PREFIX_ADDRESS = "a/";
+ private static final String PREFIX_CLIENT_TYPE = "c/";
/**
* 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.
+ *
+ * @param args The input arguments string containing the search prefix and keyword(s).
+ * @return A Command object (FindNameCommand, FindPhoneCommand, FindAddressCommand, or FindClientTypeCommand)
+ * depending on the prefix provided.
+ * @throws ParseException if the user input does not conform to the expected format,
+ * such as missing keywords or invalid prefixes.
*/
- public FindCommand parse(String args) throws ParseException {
+ public Command 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+");
+ // Check if the input starts with "n/", "p/", "a/", or "c/".
+ if (trimmedArgs.startsWith(PREFIX_NAME)) {
+ String stringName = trimmedArgs.substring(PREFIX_NAME.length()).trim();
+ String[] nameKeywords = trimmedArgs.substring(PREFIX_NAME.length()).trim().split("\\s+");
+ if (nameKeywords.length == 0 || nameKeywords[0].isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindNameCommand.MESSAGE_USAGE));
+ }
+ if (!stringName.matches("^[a-zA-Z\\s\\(\\)]+$")) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindNameCommand.MESSAGE_USAGE));
+ }
+ return new FindNameCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
- }
+ } else if (trimmedArgs.startsWith(PREFIX_PHONE)) {
+ String phoneKeywords = trimmedArgs.substring(PREFIX_PHONE.length()).trim();
+ if (phoneKeywords.isEmpty() || !phoneKeywords.matches("\\d+")) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindPhoneCommand.MESSAGE_USAGE));
+ }
+ return new FindPhoneCommand(new PhoneBeginsWithKeywordPredicate(phoneKeywords));
+
+ } else if (trimmedArgs.startsWith(PREFIX_ADDRESS)) {
+ String addressKeywords = trimmedArgs.substring(PREFIX_ADDRESS.length()).trim();
+ if (addressKeywords.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindAddressCommand.MESSAGE_USAGE));
+ }
+ return new FindAddressCommand(new AddressContainsKeywordsPredicate(addressKeywords));
+
+ } else if (trimmedArgs.startsWith(PREFIX_CLIENT_TYPE)) {
+ String clientTypeKeywords = trimmedArgs.substring(PREFIX_CLIENT_TYPE.length()).trim();
+ if (clientTypeKeywords.isEmpty() || !clientTypeKeywords.matches("^[a-zA-Z0-9\\s]+$")) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindClientTypeCommand.MESSAGE_USAGE));
+ }
+ String[] clientTypeKeywordsArr = clientTypeKeywords.split("\\s+");
+ return new FindClientTypeCommand(new ClientTypeContainsKeywordsPredicate(List.of(clientTypeKeywordsArr)));
+ } else {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+ }
}
diff --git a/src/main/java/seedu/address/logic/parser/FindNameCommandParser.java b/src/main/java/seedu/address/logic/parser/FindNameCommandParser.java
new file mode 100644
index 00000000000..4b3daab8c07
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindNameCommandParser.java
@@ -0,0 +1,36 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Arrays;
+
+import seedu.address.logic.commands.FindNameCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.NameContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FindNameCommand object
+ */
+public class FindNameCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindNameCommand
+ * and returns a FindNameCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindNameCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindNameCommand.MESSAGE_USAGE));
+ }
+ if (!trimmedArgs.matches("^[a-zA-Z()/$\\s]+$")) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindNameCommand.MESSAGE_USAGE));
+ }
+
+ String[] nameKeywords = trimmedArgs.split("\\s+");
+
+ return new FindNameCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindPhoneCommandParser.java b/src/main/java/seedu/address/logic/parser/FindPhoneCommandParser.java
new file mode 100644
index 00000000000..5ff0c7b7982
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindPhoneCommandParser.java
@@ -0,0 +1,37 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.logic.commands.FindPhoneCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.PhoneBeginsWithKeywordPredicate;
+
+/**
+ * Parses input arguments and creates a new FindPhoneCommand object
+ */
+public class FindPhoneCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindCommand
+ * and returns a FindPhoneNumberCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindPhoneCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+
+ if (trimmedArgs.isEmpty() || !trimmedArgs.matches("\\d+")) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindPhoneCommand.MESSAGE_USAGE));
+ }
+
+ String[] phoneNumber = trimmedArgs.split("\\s+");
+
+ if (phoneNumber.length != 1) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindPhoneCommand.MESSAGE_USAGE));
+ }
+
+ return new FindPhoneCommand(new PhoneBeginsWithKeywordPredicate(phoneNumber[0]));
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..4e0f53c3eac 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -2,6 +2,9 @@
import static java.util.Objects.requireNonNull;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@@ -9,11 +12,13 @@
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.StringUtil;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.clienttype.ClientType;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Description;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.reminder.ReminderDescription;
/**
* Contains utility methods used for parsing strings in the various *Parser classes.
@@ -21,6 +26,11 @@
public class ParserUtil {
public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer.";
+ public static final String MESSAGE_INVALID_DATETIME = "DateTime is not in the correct format. "
+ + "Please use the format: yyyy-MM-dd HH:mm";
+
+ // Formatter for the required DateTime format
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
/**
* Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
@@ -96,29 +106,86 @@ public static Email parseEmail(String email) throws ParseException {
}
/**
- * Parses a {@code String tag} into a {@code Tag}.
+ * Parses a {@code String clientType} into a {@code ClientType}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code clientType} is invalid.
+ */
+ public static ClientType parseClientType(String clientType) throws ParseException {
+ requireNonNull(clientType);
+ String trimmedClientType = clientType.trim();
+ if (!ClientType.isValidClientTypeName(trimmedClientType)) {
+ throw new ParseException(ClientType.MESSAGE_CONSTRAINTS);
+ }
+ return new ClientType(trimmedClientType);
+ }
+
+ /**
+ * Parses {@code Collection clientTypes} into a {@code Set}.
+ */
+ public static Set parseClientTypes(Collection clientTypes) throws ParseException {
+ requireNonNull(clientTypes);
+ final Set clientTypeSet = new HashSet<>();
+ for (String clientTypeName : clientTypes) {
+ clientTypeSet.add(parseClientType(clientTypeName));
+ }
+ return clientTypeSet;
+ }
+
+ /**
+ * Parses a {@code String description} into a {@code Description}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code tag} is invalid.
+ * @param description the string representation of a description
+ * @return a {@code Description} corresponding to the given string
+ * @throws ParseException if the given {@code description} 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 Description parseDescription(String description) throws ParseException {
+ requireNonNull(description);
+ String trimmedDescription = description.trim();
+ if (!Description.isValidDescription(trimmedDescription)) {
+ throw new ParseException(Description.MESSAGE_CONSTRAINTS);
}
- return new Tag(trimmedTag);
+ return new Description(trimmedDescription);
}
/**
- * Parses {@code Collection tags} into a {@code Set}.
+ * Parses a {@code String dateTime} into a {@code LocalDateTime}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @param dateTime the string representation of date and time in yyyy-MM-dd HH:mm format
+ * @return a {@code LocalDateTime} corresponding to the given string
+ * @throws ParseException if the given {@code dateTime} is not in the correct format
+ */
+ public static LocalDateTime parseDateTime(String dateTime) throws ParseException {
+ requireNonNull(dateTime);
+ String trimmedDateTime = dateTime.trim();
+ try {
+ return LocalDateTime.parse(trimmedDateTime, DATE_TIME_FORMATTER);
+ } catch (DateTimeParseException e) {
+ throw new ParseException(MESSAGE_INVALID_DATETIME);
+ }
+ }
+
+ /**
+ * Parses the given {@code String} description and returns a {@code ReminderDescription} object.
+ *
+ * The method trims the input description and validates it. If the description is valid,
+ * it returns a new {@code ReminderDescription} instance with the trimmed description.
+ * If the description is invalid, it throws a {@code ParseException} with an appropriate message.
+ *
+ * @param description The {@code String} description to be parsed.
+ * @return A {@code ReminderDescription} object containing the trimmed description.
+ * @throws ParseException if the given description is invalid according to {@code ReminderDescription.
+ * MESSAGE_CONSTRAINTS}.
+ * @throws NullPointerException if {@code description} is null.
*/
- 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 ReminderDescription parseReminderDescription(String description) throws ParseException {
+ requireNonNull(description);
+ String trimmedDescription = description.trim();
+ if (!Description.isValidDescription(trimmedDescription)) {
+ throw new ParseException(ReminderDescription.MESSAGE_CONSTRAINTS);
}
- return tagSet;
+ return new ReminderDescription(trimmedDescription);
}
}
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..64e2272bf2b
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ViewCommandParser.java
@@ -0,0 +1,41 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Arrays;
+
+import seedu.address.logic.commands.ViewCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.NameContainsKeywordsPredicate;
+
+/**
+ * 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();
+
+ // Check if the user input is empty, if it is, throw an error
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewCommand.MESSAGE_USAGE));
+ }
+
+ // Check for special characters - only allow letters, white space and slashes (For viewing exact names).
+ if (!trimmedArgs.matches("^[a-zA-Z()/$\\s]+$")) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewCommand.MESSAGE_USAGE));
+ }
+
+ String[] nameKeywords = trimmedArgs.split("\\s+");
+
+ return new ViewCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/reminder/AddReminderCommandParser.java b/src/main/java/seedu/address/logic/parser/reminder/AddReminderCommandParser.java
new file mode 100644
index 00000000000..82f897cd5f9
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/reminder/AddReminderCommandParser.java
@@ -0,0 +1,66 @@
+package seedu.address.logic.parser.reminder;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_TIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+
+import java.time.LocalDateTime;
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.reminder.AddReminderCommand;
+import seedu.address.logic.parser.ArgumentMultimap;
+import seedu.address.logic.parser.ArgumentTokenizer;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.Prefix;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.reminder.Reminder;
+import seedu.address.model.reminder.ReminderDescription;
+
+/**
+ * Parses input arguments and creates a new AddReminderCommand object.
+ */
+public class AddReminderCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddReminderCommand
+ * and returns an AddReminderCommand object for execution.
+ * @throws ParseException if the user input does not conform to the expected format
+ */
+ @Override
+ public AddReminderCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_DATE_TIME, PREFIX_DESCRIPTION);
+
+ // To check if fields are input correctly
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_DATE_TIME, PREFIX_DESCRIPTION)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddReminderCommand.MESSAGE_USAGE));
+ }
+
+ // Verify that each prefix is only used once
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_DATE_TIME, PREFIX_DESCRIPTION);
+
+ // Parsing each field using the updated ParserUtil methods
+ String person = argMultimap.getValue(PREFIX_NAME).get();
+ LocalDateTime dateTime = ParserUtil.parseDateTime(argMultimap.getValue(PREFIX_DATE_TIME).get());
+ ReminderDescription description = ParserUtil.parseReminderDescription(argMultimap
+ .getValue(PREFIX_DESCRIPTION).get());
+
+ // Creating a Reminder object with the parsed data
+ Reminder reminder = new Reminder(person, dateTime, description);
+
+ return new AddReminderCommand(reminder);
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+}
+
+
diff --git a/src/main/java/seedu/address/logic/parser/reminder/DeleteReminderCommandParser.java b/src/main/java/seedu/address/logic/parser/reminder/DeleteReminderCommandParser.java
new file mode 100644
index 00000000000..aa82ff4dd2d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/reminder/DeleteReminderCommandParser.java
@@ -0,0 +1,27 @@
+package seedu.address.logic.parser.reminder;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.reminder.DeleteReminderCommand;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses user input to create a new {@code DeleteReminderCommand}.
+ */
+public class DeleteReminderCommandParser implements Parser {
+
+ @Override
+ public DeleteReminderCommand parse(String userInput) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(userInput);
+ return new DeleteReminderCommand(index);
+ } catch (ParseException e) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteReminderCommand.MESSAGE_USAGE), e);
+ }
+
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/reminder/EditReminderCommandParser.java b/src/main/java/seedu/address/logic/parser/reminder/EditReminderCommandParser.java
new file mode 100644
index 00000000000..2c7bf3093d4
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/reminder/EditReminderCommandParser.java
@@ -0,0 +1,57 @@
+package seedu.address.logic.parser.reminder;
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_TIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.EditCommand;
+import seedu.address.logic.commands.reminder.EditReminderCommand;
+import seedu.address.logic.commands.reminder.EditReminderCommand.EditReminderFields;
+import seedu.address.logic.parser.ArgumentMultimap;
+import seedu.address.logic.parser.ArgumentTokenizer;
+import seedu.address.logic.parser.Parser;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses user input to create a new {@code EditReminderCommand}.
+ */
+public class EditReminderCommandParser implements Parser {
+ public EditReminderCommandParser() {
+ }
+
+ @Override
+ public EditReminderCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_DATE_TIME, PREFIX_DESCRIPTION);
+
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ EditReminderCommand.MESSAGE_USAGE), pe);
+ }
+
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_DATE_TIME, PREFIX_DESCRIPTION);
+
+ EditReminderFields editReminderFields = new EditReminderFields();
+
+ if (argMultimap.getValue(PREFIX_DATE_TIME).isPresent()) {
+ editReminderFields.setDateTime(ParserUtil.parseDateTime(argMultimap.getValue(PREFIX_DATE_TIME).get()));
+ }
+ if (argMultimap.getValue(PREFIX_DESCRIPTION).isPresent()) {
+ editReminderFields.setDescription(ParserUtil.parseReminderDescription(
+ argMultimap.getValue(PREFIX_DESCRIPTION).get()));
+ }
+
+ if (!editReminderFields.isAnyFieldEdited()) {
+ throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
+ }
+
+ return new EditReminderCommand(index, editReminderFields);
+ }
+}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
deleted file mode 100644
index 73397161e84..00000000000
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package seedu.address.model;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.List;
-
-import javafx.collections.ObservableList;
-import seedu.address.commons.util.ToStringBuilder;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.UniquePersonList;
-
-/**
- * Wraps all data at the address-book level
- * Duplicates are not allowed (by .isSamePerson comparison)
- */
-public class AddressBook implements ReadOnlyAddressBook {
-
- private final UniquePersonList persons;
-
- /*
- * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
- * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
- *
- * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication
- * among constructors.
- */
- {
- persons = new UniquePersonList();
- }
-
- public AddressBook() {}
-
- /**
- * Creates an AddressBook using the Persons in the {@code toBeCopied}
- */
- public AddressBook(ReadOnlyAddressBook toBeCopied) {
- this();
- resetData(toBeCopied);
- }
-
- //// list overwrite operations
-
- /**
- * Replaces the contents of the person list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- this.persons.setPersons(persons);
- }
-
- /**
- * Resets the existing data of this {@code AddressBook} with {@code newData}.
- */
- public void resetData(ReadOnlyAddressBook newData) {
- requireNonNull(newData);
-
- setPersons(newData.getPersonList());
- }
-
- //// person-level operations
-
- /**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
- */
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return persons.contains(person);
- }
-
- /**
- * Adds a person to the address book.
- * The person must not already exist in the address book.
- */
- public void addPerson(Person p) {
- persons.add(p);
- }
-
- /**
- * Replaces the given person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireNonNull(editedPerson);
-
- persons.setPerson(target, editedPerson);
- }
-
- /**
- * Removes {@code key} from this {@code AddressBook}.
- * {@code key} must exist in the address book.
- */
- public void removePerson(Person key) {
- persons.remove(key);
- }
-
- //// util methods
-
- @Override
- public String toString() {
- return new ToStringBuilder(this)
- .add("persons", persons)
- .toString();
- }
-
- @Override
- public ObservableList getPersonList() {
- return persons.asUnmodifiableObservableList();
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof AddressBook)) {
- return false;
- }
-
- AddressBook otherAddressBook = (AddressBook) other;
- return persons.equals(otherAddressBook.persons);
- }
-
- @Override
- public int hashCode() {
- return persons.hashCode();
- }
-}
diff --git a/src/main/java/seedu/address/model/ClientHub.java b/src/main/java/seedu/address/model/ClientHub.java
new file mode 100644
index 00000000000..4ad74834863
--- /dev/null
+++ b/src/main/java/seedu/address/model/ClientHub.java
@@ -0,0 +1,250 @@
+package seedu.address.model;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.UniquePersonList;
+import seedu.address.model.reminder.Reminder;
+import seedu.address.model.reminder.ReminderList;
+
+
+/**
+ * Wraps all data at the address-book level.
+ * Duplicates are not allowed (by .isSamePerson comparison).
+ */
+public class ClientHub implements ReadOnlyClientHub {
+
+ private final UniquePersonList persons;
+ private final ReminderList reminders;
+
+ /*
+ * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
+ * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
+ *
+ * Note that non-static init blocks are not recommended to use. There are aother ways to avoid duplication
+ * among constructors.
+ */
+ {
+ persons = new UniquePersonList();
+ reminders = new ReminderList();
+ }
+
+ /**
+ * Creates an empty ClientHub.
+ */
+ public ClientHub() {}
+
+ /**
+ * Creates a ClientHub using the data from the given {@code toBeCopied}.
+ *
+ * @param toBeCopied The ReadOnlyClientHub to copy data from.
+ */
+ public ClientHub(ReadOnlyClientHub toBeCopied) {
+ this();
+ resetData(toBeCopied);
+ }
+
+ //// list overwrite operations
+
+ /**
+ * Replaces the contents of the person list with the specified {@code persons}.
+ * The list must not contain duplicate persons.
+ *
+ * @param persons The list of persons to set.
+ */
+ public void setPersons(List persons) {
+ this.persons.setPersons(persons);
+ }
+
+ /**
+ * Replaces the contents of the reminder list with the specified {@code reminders}.
+ * The list must not contain duplicate reminders.
+ *
+ * @param reminders The list of reminders to set.
+ */
+ public void setReminders(List reminders) {
+ this.reminders.setReminders(reminders);
+ }
+
+ /**
+ * Resets the existing data of this ClientHub with the specified {@code newData}.
+ *
+ * @param newData The new data to reset with.
+ */
+ public void resetData(ReadOnlyClientHub newData) {
+ requireNonNull(newData);
+
+ setPersons(newData.getPersonList());
+ setReminders(newData.getReminderList());
+ }
+
+ //// person-level operations
+
+ /**
+ * Checks if a person with the same identity as the specified {@code person} exists in the address book.
+ *
+ * @param person The person to check.
+ * @return True if the person exists, false otherwise.
+ */
+ public boolean hasPerson(Person person) {
+ requireNonNull(person);
+ return persons.contains(person);
+ }
+
+ /**
+ * Checks if a reminder with the same identity as the specified {@code reminder} exists in the address book.
+ *
+ * @param reminder The reminder to check.
+ * @return True if the reminder exists, false otherwise.
+ */
+ public boolean hasReminder(Reminder reminder) {
+ requireNonNull(reminder);
+ return reminders.contains(reminder);
+ }
+
+ /**
+ * Adds a person to the address book.
+ * The person must not already exist in the address book.
+ *
+ * @param p The person to add.
+ */
+ public void addPerson(Person p) {
+ persons.add(p);
+ }
+
+ /**
+ * Adds a reminder to the address book.
+ * The reminder must not already exist in the address book.
+ *
+ * @param r The reminder to add.
+ */
+ public void addReminder(Reminder r) {
+ reminders.add(r);
+ }
+
+ /**
+ * Replaces the specified {@code target} person in the list with {@code editedPerson}.
+ * The {@code target} must exist in the address book, and the {@code editedPerson} must not have the
+ * same identity as another existing person in the address book.
+ *
+ * @param target The person to replace.
+ * @param editedPerson The new person to replace with.
+ */
+ public void setPerson(Person target, Person editedPerson) {
+ requireNonNull(editedPerson);
+
+ persons.setPerson(target, editedPerson);
+ }
+
+ /**
+ * Replaces the specified {@code target} reminder in the list with {@code editedReminder}.
+ * The {@code target} must exist in the address book.
+ *
+ * @param target The reminder to replace.
+ * @param editedReminder The new reminder to replace with.
+ */
+ public void setReminder(Reminder target, Reminder editedReminder) {
+ requireNonNull(editedReminder);
+
+ reminders.setReminder(target, editedReminder);
+ }
+
+ /**
+ * Removes the specified {@code key} person from this ClientHub.
+ * The person must exist in the address book.
+ *
+ * @param key The person to remove.
+ */
+ public void removePerson(Person key) {
+ persons.remove(key);
+ }
+
+ /**
+ * Removes the specified {@code key} reminder from this ClientHub.
+ * The reminder must exist in the address book.
+ *
+ * @param key The reminder to remove.
+ */
+ public void removeReminder(Reminder key) {
+ reminders.remove(key);
+ }
+
+ //// util methods
+
+ /**
+ * Returns a string representation of the ClientHub, including the person and reminder lists.
+ *
+ * @return A string representation of the ClientHub.
+ */
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("persons", persons)
+ .add("reminders", reminders)
+ .toString();
+ }
+
+ /**
+ * Returns the person list as an unmodifiable observable list.
+ *
+ * @return The person list.
+ */
+ @Override
+ public ObservableList getPersonList() {
+ return persons.asUnmodifiableObservableList();
+ }
+
+ /**
+ * Returns the reminder list as an unmodifiable observable list.
+ *
+ * @return The reminder list.
+ */
+ public ObservableList getReminders() {
+ return reminders.asUnmodifiableObservableList();
+ }
+
+ public ObservableList getReminderList() {
+ ObservableList temp = FXCollections.observableArrayList(
+ persons.stream()
+ .flatMap(person -> person.getReminders().stream())
+ .collect(Collectors.toList()));
+ reminders.setReminders(temp);
+ return reminders.asUnmodifiableObservableList();
+ }
+
+ /**
+ * Checks if this ClientHub is equal to another object.
+ *
+ * @param other The object to compare with.
+ * @return True if equal, false otherwise.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof ClientHub)) {
+ return false;
+ }
+
+ ClientHub otherClientHub = (ClientHub) other;
+ return persons.equals(otherClientHub.persons) && reminders.equals(otherClientHub.reminders);
+ }
+
+ /**
+ * Returns the hash code of this ClientHub.
+ *
+ * @return The hash code.
+ */
+ @Override
+ public int hashCode() {
+ return persons.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
index d54df471c1f..3129f0ff1a1 100644
--- a/src/main/java/seedu/address/model/Model.java
+++ b/src/main/java/seedu/address/model/Model.java
@@ -1,11 +1,13 @@
package seedu.address.model;
import java.nio.file.Path;
+import java.util.Comparator;
import java.util.function.Predicate;
import javafx.collections.ObservableList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.model.person.Person;
+import seedu.address.model.reminder.Reminder;
/**
* The API of the Model component.
@@ -13,6 +15,7 @@
public interface Model {
/** {@code Predicate} that always evaluate to true */
Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true;
+ Predicate PREDICATE_SHOW_ALL_REMINDERS = unused -> true;
/**
* Replaces user prefs data with the data in {@code userPrefs}.
@@ -37,38 +40,54 @@ public interface Model {
/**
* Returns the user prefs' address book file path.
*/
- Path getAddressBookFilePath();
+ Path getClientHubFilePath();
/**
* Sets the user prefs' address book file path.
*/
- void setAddressBookFilePath(Path addressBookFilePath);
+ void setClientHubFilePath(Path clientHubFilePath);
/**
- * Replaces address book data with the data in {@code addressBook}.
+ * Replaces address book data with the data in {@code clientHub}.
*/
- void setAddressBook(ReadOnlyAddressBook addressBook);
+ void setClientHub(ReadOnlyClientHub clientHub);
- /** Returns the AddressBook */
- ReadOnlyAddressBook getAddressBook();
+ /** Returns the ClientHub */
+ ReadOnlyClientHub getClientHub();
/**
* Returns true if a person with the same identity as {@code person} exists in the address book.
*/
boolean hasPerson(Person person);
+ /**
+ * Returns true if a reminder with the same identity as {@code reminder} exists in the address book.
+ */
+ boolean hasReminder(Reminder reminder);
+
/**
* Deletes the given person.
* The person must exist in the address book.
*/
void deletePerson(Person target);
+ /**
+ * Deletes the given reminder.
+ * The reminder must exist in the address book.
+ */
+ void deleteReminder(Reminder target);
+
/**
* Adds the given person.
* {@code person} must not already exist in the address book.
*/
void addPerson(Person person);
+ /**
+ * Adds the given reminder.
+ * {@code reminder} must not already exist in the address book.
+ */
+ void addReminder(Reminder reminder);
/**
* Replaces the given person {@code target} with {@code editedPerson}.
* {@code target} must exist in the address book.
@@ -76,12 +95,49 @@ public interface Model {
*/
void setPerson(Person target, Person editedPerson);
+ /**
+ * Replaces the given reminder {@code target} with {@code editedReminder}.
+ * {@code target} must exist in the address book.
+ * The reminder identity of {@code editedReminder}
+ */
+ void setReminder(Reminder target, Reminder editedReminder);
+ /**
+ * Returns the number of persons in the address book.
+ */
+ int getDisplayPersonsListSize();
+
+ /**
+ * Returns the number of reminders in the address book.
+ */
+ int getDisplayRemindersListSize();
+
/** Returns an unmodifiable view of the filtered person list */
- ObservableList getFilteredPersonList();
+ ObservableList getDisplayPersons();
+
+ /** Returns an unmodifiable view of the filtered reminder list */
+ ObservableList getDisplayReminders();
+
+ /** Updates the current list to display all contacts in the list */
+ void updateUnfilteredList();
+
+ /** Updates the current list to display all reminders in the list */
+ void updateUnfilteredReminderList();
/**
- * Updates the filter of the filtered person list to filter by the given {@code predicate}.
+ * Updates the current list to filter by the given {@code predicate}.
* @throws NullPointerException if {@code predicate} is null.
*/
void updateFilteredPersonList(Predicate predicate);
+
+ /**
+ * Updates the current list to filter by the given {@code predicate}.
+ * @throws NullPointerException if {@code predicate} is null.
+ */
+ void updateFilteredReminderList();
+
+ /**
+ * Updates the current list to sort by the given {@code comparator}.
+ * @throws NullPointerException if {@code comparator} is null.
+ */
+ void updateSortedPersonList(Comparator comparator);
}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
index 57bc563fde6..15fa296987c 100644
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ b/src/main/java/seedu/address/model/ModelManager.java
@@ -4,14 +4,17 @@
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
import java.nio.file.Path;
+import java.util.Comparator;
import java.util.function.Predicate;
import java.util.logging.Logger;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
+import javafx.collections.transformation.SortedList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
import seedu.address.model.person.Person;
+import seedu.address.model.reminder.Reminder;
/**
* Represents the in-memory model of the address book data.
@@ -19,25 +22,40 @@
public class ModelManager implements Model {
private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
- private final AddressBook addressBook;
+ private final ClientHub clientHub;
private final UserPrefs userPrefs;
+ private final ObservableList originalPersons;
private final FilteredList filteredPersons;
+ private final SortedList sortedPersons;
+ private final ObservableList originalReminders;
+ private final FilteredList filteredReminders;
+ private final SortedList sortedReminders;
+
/**
- * Initializes a ModelManager with the given addressBook and userPrefs.
+ * Initializes a ModelManager with the given clientHub and userPrefs.
*/
- public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) {
- requireAllNonNull(addressBook, userPrefs);
+ public ModelManager(ReadOnlyClientHub clientHub, ReadOnlyUserPrefs userPrefs) {
+ requireAllNonNull(clientHub, userPrefs);
- logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);
+ logger.fine("Initializing with clienthub: " + clientHub + " and user prefs " + userPrefs);
- this.addressBook = new AddressBook(addressBook);
+ this.clientHub = new ClientHub(clientHub);
this.userPrefs = new UserPrefs(userPrefs);
- filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
+ this.originalPersons = this.clientHub.getPersonList();
+ this.filteredPersons = new FilteredList<>(originalPersons);
+ this.sortedPersons = new SortedList<>(filteredPersons);
+
+ this.originalReminders = this.clientHub.getReminderList();
+ this.filteredReminders = new FilteredList<>(originalReminders);
+ this.sortedReminders = new SortedList<>(filteredReminders);
+
+ filteredPersons.setPredicate(PREDICATE_SHOW_ALL_PERSONS);
+ updateFilteredReminderList();
}
public ModelManager() {
- this(new AddressBook(), new UserPrefs());
+ this(new ClientHub(), new UserPrefs());
}
//=========== UserPrefs ==================================================================================
@@ -65,69 +83,150 @@ public void setGuiSettings(GuiSettings guiSettings) {
}
@Override
- public Path getAddressBookFilePath() {
- return userPrefs.getAddressBookFilePath();
+ public Path getClientHubFilePath() {
+ return userPrefs.getClientHubFilePath();
}
@Override
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- userPrefs.setAddressBookFilePath(addressBookFilePath);
+ public void setClientHubFilePath(Path clientHubFilePath) {
+ requireNonNull(clientHubFilePath);
+ userPrefs.setClientHubFilePath(clientHubFilePath);
}
- //=========== AddressBook ================================================================================
+ //=========== ClientHub ================================================================================
@Override
- public void setAddressBook(ReadOnlyAddressBook addressBook) {
- this.addressBook.resetData(addressBook);
+ public void setClientHub(ReadOnlyClientHub clientHub) {
+ this.clientHub.resetData(clientHub);
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
- return addressBook;
+ public ReadOnlyClientHub getClientHub() {
+ return clientHub;
}
@Override
public boolean hasPerson(Person person) {
requireNonNull(person);
- return addressBook.hasPerson(person);
+ return clientHub.hasPerson(person);
+ }
+
+ @Override
+ public boolean hasReminder(Reminder reminder) {
+ requireNonNull(reminder);
+ return clientHub.hasReminder(reminder);
}
@Override
public void deletePerson(Person target) {
- addressBook.removePerson(target);
+ clientHub.removePerson(target);
+ }
+
+ @Override
+ public void deleteReminder(Reminder target) {
+ clientHub.removeReminder(target);
}
@Override
public void addPerson(Person person) {
- addressBook.addPerson(person);
+ clientHub.addPerson(person);
updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
}
+ @Override
+ public void addReminder(Reminder reminder) {
+ clientHub.addReminder(reminder);
+ updateFilteredReminderList();
+ }
+
@Override
public void setPerson(Person target, Person editedPerson) {
requireAllNonNull(target, editedPerson);
- addressBook.setPerson(target, editedPerson);
+ clientHub.setPerson(target, editedPerson);
}
- //=========== Filtered Person List Accessors =============================================================
+ @Override
+ public void setReminder(Reminder target, Reminder editedReminder) {
+ requireAllNonNull(target, editedReminder);
+
+ clientHub.setReminder(target, editedReminder);
+ }
+
+ @Override
+ public int getDisplayPersonsListSize() {
+ return this.getDisplayPersons().size();
+ }
+
+ @Override
+ public int getDisplayRemindersListSize() {
+ return this.getDisplayReminders().size();
+ }
/**
* Returns an unmodifiable view of the list of {@code Person} backed by the internal list of
- * {@code versionedAddressBook}
+ * {@code versionedClientHub}
*/
@Override
- public ObservableList getFilteredPersonList() {
- return filteredPersons;
+ public ObservableList getDisplayPersons() {
+ return sortedPersons;
}
+ @Override
+ public ObservableList getDisplayReminders() {
+ return sortedReminders;
+ }
+
+ //=========== Unfiltered Person List Accessors =============================================================
+
+ @Override
+ public void updateUnfilteredList() {
+ // Reset the filter to show all persons
+ filteredPersons.setPredicate(PREDICATE_SHOW_ALL_PERSONS);
+
+ // Remove any sorting in the list
+ sortedPersons.setComparator(null);
+
+ // Force resort to match original list order if needed
+ sortedPersons.setComparator((p1, p2) -> 0); // Force a resort
+ sortedPersons.setComparator(null); // Remove the comparator
+ }
+
+ //=========== Unfiltered Reminder List Accessors =============================================================
+
+ @Override
+ public void updateUnfilteredReminderList() {
+ // Reset the filter to show all reminders
+ filteredReminders.setPredicate(PREDICATE_SHOW_ALL_REMINDERS);
+ }
+
+ //=========== Filtered Person List Accessors =============================================================
+
@Override
public void updateFilteredPersonList(Predicate predicate) {
requireNonNull(predicate);
filteredPersons.setPredicate(predicate);
}
+ //=========== Filtered Reminder List Accessors =============================================================
+
+ @Override
+ public void updateFilteredReminderList() {
+ filteredReminders.setPredicate(PREDICATE_SHOW_ALL_REMINDERS);
+
+ Comparator reminderComparator = Comparator.comparing(Reminder::getDateTime);
+
+ sortedReminders.setComparator(reminderComparator);
+ }
+
+ //=========== Sorted Person List Accessors =============================================================
+
+ @Override
+ public void updateSortedPersonList(Comparator comparator) {
+ requireNonNull(comparator);
+ sortedPersons.setComparator(comparator);
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -140,9 +239,13 @@ public boolean equals(Object other) {
}
ModelManager otherModelManager = (ModelManager) other;
- return addressBook.equals(otherModelManager.addressBook)
+ return clientHub.equals(otherModelManager.clientHub)
&& userPrefs.equals(otherModelManager.userPrefs)
- && filteredPersons.equals(otherModelManager.filteredPersons);
+ && originalPersons.equals(otherModelManager.originalPersons)
+ && filteredPersons.equals(otherModelManager.filteredPersons)
+ && sortedPersons.equals(otherModelManager.sortedPersons)
+ && originalReminders.equals(otherModelManager.originalReminders)
+ && filteredReminders.equals(otherModelManager.filteredReminders);
}
}
diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
deleted file mode 100644
index 6ddc2cd9a29..00000000000
--- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package seedu.address.model;
-
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-
-/**
- * Unmodifiable view of an address book
- */
-public interface ReadOnlyAddressBook {
-
- /**
- * Returns an unmodifiable view of the persons list.
- * This list will not contain any duplicate persons.
- */
- ObservableList getPersonList();
-
-}
diff --git a/src/main/java/seedu/address/model/ReadOnlyClientHub.java b/src/main/java/seedu/address/model/ReadOnlyClientHub.java
new file mode 100644
index 00000000000..9a306126070
--- /dev/null
+++ b/src/main/java/seedu/address/model/ReadOnlyClientHub.java
@@ -0,0 +1,19 @@
+package seedu.address.model;
+
+import javafx.collections.ObservableList;
+import seedu.address.model.person.Person;
+import seedu.address.model.reminder.Reminder;
+
+/**
+ * Unmodifiable view of an address book
+ */
+public interface ReadOnlyClientHub {
+
+ /**
+ * Returns an unmodifiable view of the persons list and reminder list.
+ * person list will not contain any duplicate persons.
+ */
+ ObservableList getPersonList();
+ ObservableList getReminderList();
+
+}
diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
index befd58a4c73..1cff694b5f7 100644
--- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
+++ b/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
@@ -11,6 +11,6 @@ public interface ReadOnlyUserPrefs {
GuiSettings getGuiSettings();
- Path getAddressBookFilePath();
+ Path getClientHubFilePath();
}
diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/address/model/UserPrefs.java
index 6be655fb4c7..e722de18623 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 clientHubFilePath = Paths.get("data" , "clienthub.json");
/**
* Creates a {@code UserPrefs} with default values.
@@ -35,7 +35,7 @@ public UserPrefs(ReadOnlyUserPrefs userPrefs) {
public void resetData(ReadOnlyUserPrefs newUserPrefs) {
requireNonNull(newUserPrefs);
setGuiSettings(newUserPrefs.getGuiSettings());
- setAddressBookFilePath(newUserPrefs.getAddressBookFilePath());
+ setClientHubFilePath(newUserPrefs.getClientHubFilePath());
}
public GuiSettings getGuiSettings() {
@@ -47,13 +47,13 @@ public void setGuiSettings(GuiSettings guiSettings) {
this.guiSettings = guiSettings;
}
- public Path getAddressBookFilePath() {
- return addressBookFilePath;
+ public Path getClientHubFilePath() {
+ return clientHubFilePath;
}
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- this.addressBookFilePath = addressBookFilePath;
+ public void setClientHubFilePath(Path clientHubFilePath) {
+ requireNonNull(clientHubFilePath);
+ this.clientHubFilePath = clientHubFilePath;
}
@Override
@@ -69,19 +69,19 @@ public boolean equals(Object other) {
UserPrefs otherUserPrefs = (UserPrefs) other;
return guiSettings.equals(otherUserPrefs.guiSettings)
- && addressBookFilePath.equals(otherUserPrefs.addressBookFilePath);
+ && clientHubFilePath.equals(otherUserPrefs.clientHubFilePath);
}
@Override
public int hashCode() {
- return Objects.hash(guiSettings, addressBookFilePath);
+ return Objects.hash(guiSettings, clientHubFilePath);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Gui Settings : " + guiSettings);
- sb.append("\nLocal data file location : " + addressBookFilePath);
+ sb.append("\nLocal data file location : " + clientHubFilePath);
return sb.toString();
}
diff --git a/src/main/java/seedu/address/model/clienttype/ClientType.java b/src/main/java/seedu/address/model/clienttype/ClientType.java
new file mode 100644
index 00000000000..4aaf2e49f29
--- /dev/null
+++ b/src/main/java/seedu/address/model/clienttype/ClientType.java
@@ -0,0 +1,63 @@
+package seedu.address.model.clienttype;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a ClientType in the address book.
+ * Guarantees: immutable; name is valid as declared in {@link #isValidClientTypeName(String)}
+ */
+public class ClientType {
+
+ public static final String MESSAGE_CONSTRAINTS = "ClientTypes names should be "
+ + "alphanumeric and only up to 30 characters long(space inclusive)";
+ public static final String VALIDATION_REGEX = "[\\p{Alnum} ]{1,30}";
+
+ public final String clientTypeName;
+
+ /**
+ * Constructs a {@code ClientType}.
+ *
+ * @param clientTypeName A valid client type name.
+ */
+ public ClientType(String clientTypeName) {
+ requireNonNull(clientTypeName);
+ checkArgument(isValidClientTypeName(clientTypeName), MESSAGE_CONSTRAINTS);
+ this.clientTypeName = clientTypeName;
+ }
+
+ /**
+ * Returns true if a given string is a valid client type name.
+ */
+ public static boolean isValidClientTypeName(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ClientType)) {
+ return false;
+ }
+
+ ClientType otherClientType = (ClientType) other;
+ return clientTypeName.equals(otherClientType.clientTypeName);
+ }
+
+ @Override
+ public int hashCode() {
+ return clientTypeName.hashCode();
+ }
+
+ /**
+ * Format state as text for viewing.
+ */
+ public String toString() {
+ return '[' + clientTypeName + ']';
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java
index 469a2cc9a1e..6d905244f4c 100644
--- a/src/main/java/seedu/address/model/person/Address.java
+++ b/src/main/java/seedu/address/model/person/Address.java
@@ -9,14 +9,14 @@
*/
public class Address {
- public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank";
+ public static final String MESSAGE_CONSTRAINTS = "Addresses can only take in letters, numbers or "
+ + "the following characters: ,#-():; "
+ + "\nIt should not be blank.";
/*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
+ * Address should only contain ",#-():;", letters or alphabets.
*/
- public static final String VALIDATION_REGEX = "[^\\s].*";
-
+ public static final String VALIDATION_REGEX = "^(?=.*\\S)[a-zA-Z0-9#\\-(),:;\\s]+$";
public final String value;
/**
diff --git a/src/main/java/seedu/address/model/person/AddressContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/AddressContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..74dc30a0618
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/AddressContainsKeywordsPredicate.java
@@ -0,0 +1,47 @@
+package seedu.address.model.person;
+
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s {@code Address} matches any of the keywords given.
+ */
+public class AddressContainsKeywordsPredicate implements Predicate {
+
+ private final String keywords;
+
+ public AddressContainsKeywordsPredicate(String keywords) {
+ this.keywords = keywords.trim();
+ }
+
+ @Override
+ public boolean test(Person person) {
+ if (keywords.isEmpty()) {
+ return false;
+ }
+ // Check if any of the keywords match any part of the address
+ return person.getAddress().value.toLowerCase().contains(keywords.toLowerCase());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof AddressContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ AddressContainsKeywordsPredicate otherAddressContainsKeywordsPredicate =
+ (AddressContainsKeywordsPredicate) other;
+ return keywords.equals(otherAddressContainsKeywordsPredicate.keywords);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("keywords", keywords).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/ClientTypeContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/ClientTypeContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..76a61597eba
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/ClientTypeContainsKeywordsPredicate.java
@@ -0,0 +1,78 @@
+package seedu.address.model.person;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.model.clienttype.ClientType;
+
+/**
+ * Tests that a {@code Person}'s {@code Client_Type} matches any of the keywords given.
+ */
+public class ClientTypeContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public ClientTypeContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ Set personClientTypes = person.getClientTypes();
+
+ // If the client type list is empty, return false -> no client type to match (Invalid Client Type)
+ if (this.keywords.isEmpty()) {
+ return false;
+ }
+
+ // Try matching the combined phrase first
+ String combinedPhrase = String.join(" ", keywords).toLowerCase();
+ if (personClientTypes.stream().anyMatch(clientType ->
+ clientType.clientTypeName.toLowerCase().contains(combinedPhrase))) {
+ return true;
+ }
+
+ // Split each client type into individual words and flatten into a single stream of words
+ Set clientTypeWords = personClientTypes.stream()
+ .map(clientType -> clientType.clientTypeName.toLowerCase().split("\\s+"))
+ .flatMap(Arrays::stream)
+ .collect(Collectors.toSet());
+
+ // Check if all keywords match at least one of the client type words
+ return keywords.stream()
+ .allMatch(keyword -> clientTypeWords.stream()
+ .anyMatch(word -> word.startsWith(keyword.toLowerCase())));
+
+
+
+ // // If combined phrase does not match, try matching individual keywords
+ // return keywords.stream()
+ // .allMatch(keyword -> personClientTypes.stream().anyMatch(clientType ->
+ // clientType.clientTypeName.toLowerCase().startsWith(keyword.toLowerCase()))
+ // );
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ClientTypeContainsKeywordsPredicate)) {
+ return false;
+ }
+
+ ClientTypeContainsKeywordsPredicate otherNameContainsKeywordsPredicate =
+ (ClientTypeContainsKeywordsPredicate) other;
+ return keywords.equals(otherNameContainsKeywordsPredicate.keywords);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("keywords", keywords).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Description.java b/src/main/java/seedu/address/model/person/Description.java
new file mode 100644
index 00000000000..1a5e5c94bb5
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/Description.java
@@ -0,0 +1,66 @@
+package seedu.address.model.person;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Description in the system.
+ * Guarantees: immutable; is valid as declared in {@link #VALIDATION_REGEX}
+ */
+public class Description {
+ public static final String MESSAGE_CONSTRAINTS = "Descriptions can take any values but not more than 500"
+ + "characters";
+
+ // Allow printable characters excluding control characters
+ public static final String VALIDATION_REGEX = "^[\\p{Print}&&[^\\p{Cntrl}]]*$";
+
+ public static final int MAX_LENGTH = 500;
+ public static final int MIN_LENGTH = 1;
+
+ public final String description;
+
+ /**
+ * Constructs a {@code Description}.
+ *
+ * @param description A valid description.
+ */
+ public Description(String description) {
+ requireNonNull(description);
+ checkArgument(isValidDescription(description), MESSAGE_CONSTRAINTS);
+ this.description = description;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Description)) {
+ return false;
+ }
+
+ Description otherDescription = (Description) other;
+ return description.equals(otherDescription.description);
+ }
+
+ @Override
+ public int hashCode() {
+ return description.hashCode();
+ }
+
+ /**
+ * Format state as text for viewing.
+ */
+ public String toString() {
+ return '[' + description + ']';
+ }
+
+ /**
+ * Returns true if a given string is a valid description.
+ */
+ public static boolean isValidDescription(String test) {
+ return test.matches(VALIDATION_REGEX)
+ && test.trim().length() <= MAX_LENGTH && test.trim().length() >= MIN_LENGTH;
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/person/Name.java
index 173f15b9b00..16688871eaf 100644
--- a/src/main/java/seedu/address/model/person/Name.java
+++ b/src/main/java/seedu/address/model/person/Name.java
@@ -10,13 +10,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, space, parenthesis and slash, and it should not be blank. Names should "
+ + "start with a letter and end with a letter or closing bracket.";
/*
* The first character of the address must not be a whitespace,
* otherwise " " (a blank string) becomes a valid input.
*/
- public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+ public static final String VALIDATION_REGEX = "^[a-zA-Z]+[a-zA-Z()/\\s]*[a-zA-Z)]$";
+
public final String fullName;
@@ -28,7 +30,18 @@ public class Name {
public Name(String name) {
requireNonNull(name);
checkArgument(isValidName(name), MESSAGE_CONSTRAINTS);
- fullName = name;
+
+ String[] words = name.split(" ");
+ String result = "";
+
+ for (String word : words) {
+ if (word.length() > 0) {
+ result += Character.toUpperCase(word.charAt(0)) + word.substring(1).toLowerCase() + " ";
+ }
+ }
+
+ // Remove the extra trailing space and return the result
+ fullName = result.trim();
}
/**
@@ -56,7 +69,11 @@ public boolean equals(Object other) {
}
Name otherName = (Name) other;
- return fullName.equals(otherName.fullName);
+
+ // Compare the full name of the person
+ // John Doe will match john doe
+ // To prevent duplicate names from getting added.
+ return fullName.equalsIgnoreCase(otherName.fullName);
}
@Override
diff --git a/src/main/java/seedu/address/model/person/NameComparator.java b/src/main/java/seedu/address/model/person/NameComparator.java
new file mode 100644
index 00000000000..8e4076216bc
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/NameComparator.java
@@ -0,0 +1,38 @@
+package seedu.address.model.person;
+
+import java.util.Comparator;
+
+/**
+ * Compares that a {@code Person}'s {@code Name} is bigger than the other.
+ */
+public class NameComparator implements Comparator {
+ public NameComparator() {}
+
+ @Override
+ public int compare(Person person1, Person person2) {
+ int comparison = person1.getName().fullName.compareTo(person2.getName().fullName);
+
+ assert comparison != 0; // ensures no repeats of person
+
+ return comparison;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof NameComparator)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsDeletePredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsDeletePredicate.java
new file mode 100644
index 00000000000..d7185a9fb52
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/NameContainsKeywordsDeletePredicate.java
@@ -0,0 +1,107 @@
+package seedu.address.model.person;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s name matches any of the specified keywords.
+ */
+public class NameContainsKeywordsDeletePredicate implements Predicate {
+ private final List keywords;
+
+ /**
+ * Constructs a {@code NameContainsKeywordsDeletePredicate} with the specified keywords.
+ *
+ * @param keywords A list of keywords to match against the {@code Person}'s name.
+ */
+ public NameContainsKeywordsDeletePredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ /**
+ * Evaluates this predicate on the given argument.
+ *
+ * @param person The person to test.
+ * @return {@code true} if the person's name matches the predicate's criteria, otherwise {@code false}.
+ * Returns {@code true} if all keywords are found in the person's name, or if the last keyword
+ * ends with a "/", indicating an exact match.
+ */
+ @Override
+ public boolean test(Person person) {
+ if (keywords.isEmpty()) {
+ return false;
+ } else if (keywords.get(keywords.size() - 1).contains("$")) {
+ return isExact(person);
+ } else {
+ String[] nameParts = person.getName().fullName.split("\\s+");
+ // Create a list to track which name parts have been matched
+ List remainingParts = new ArrayList<>(Arrays.asList(nameParts));
+
+ for (String keyword : keywords) {
+ boolean foundMatch = false;
+ // Try to match this keyword with any remaining (unmatched) name part
+ for (int i = remainingParts.size() - 1; i >= 0; i--) {
+ if (remainingParts.get(i).toLowerCase().startsWith(keyword.toLowerCase())) {
+ remainingParts.remove(i);
+ foundMatch = true;
+ break;
+ }
+ }
+ // If any keyword doesn't find a match, return false
+ if (!foundMatch) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Checks if the person's name is an exact match with the concatenated keywords.
+ *
+ * @param person The person to compare against the concatenated keywords.
+ * @return {@code true} if the concatenated keywords, without the trailing "/", match the person's full name.
+ */
+ public boolean isExact(Person person) {
+ String fullname = String.join("", keywords).toLowerCase().split("\\$")[0].trim();
+ String personName = person.getName().fullName.trim().toLowerCase().replace(" ", "");
+ return fullname.equals(personName);
+ }
+
+ /**
+ * Checks if this predicate is equal to another object.
+ *
+ * @param other The other object to compare.
+ * @return {@code true} if the other object is an instance of {@code NameContainsKeywordsDeletePredicate}
+ * and has the same keywords, otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof NameContainsKeywordsDeletePredicate)) {
+ return false;
+ }
+
+ NameContainsKeywordsDeletePredicate otherNameContainsKeywordsDeletePredicate =
+ (NameContainsKeywordsDeletePredicate) other;
+ return keywords.equals(otherNameContainsKeywordsDeletePredicate.keywords);
+ }
+
+ /**
+ * Returns a string representation of this predicate.
+ *
+ * @return A string that includes the list of keywords.
+ */
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("keywords", keywords).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
index 62d19be2977..d8e5fb735a2 100644
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
@@ -1,9 +1,10 @@
package seedu.address.model.person;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
-import seedu.address.commons.util.StringUtil;
import seedu.address.commons.util.ToStringBuilder;
/**
@@ -18,8 +19,45 @@ public NameContainsKeywordsPredicate(List keywords) {
@Override
public boolean test(Person person) {
- return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
+ if (keywords.isEmpty()) {
+ return false;
+ } else if (keywords.get(keywords.size() - 1).contains("$")) {
+ return isExact(person);
+ } else {
+ String[] nameParts = person.getName().fullName.split("\\s+");
+ // Create a list to track which name parts have been matched
+ List remainingParts = new ArrayList<>(Arrays.asList(nameParts));
+
+ for (String keyword : keywords) {
+ boolean foundMatch = false;
+ // Try to match this keyword with any remaining (unmatched) name part
+ for (int i = remainingParts.size() - 1; i >= 0; i--) {
+ if (remainingParts.get(i).toLowerCase().startsWith(keyword.toLowerCase())) {
+ remainingParts.remove(i);
+ foundMatch = true;
+ break;
+ }
+ }
+ // If any keyword doesn't find a match, return false
+ if (!foundMatch) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+
+ /**
+ * Checks if the person's name is an exact match with the concatenated keywords.
+ *
+ * @param person The person to compare against the concatenated keywords.
+ * @return {@code true} if the concatenated keywords, match the person's full name.
+ */
+ public boolean isExact(Person person) {
+ String fullname = String.join("", keywords).toLowerCase().split("\\$")[0].trim();
+ String personName = person.getName().fullName.trim().toLowerCase().replace(" ", "");
+ return fullname.equals(personName);
}
@Override
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
index abe8c46b535..64226b9fc51 100644
--- a/src/main/java/seedu/address/model/person/Person.java
+++ b/src/main/java/seedu/address/model/person/Person.java
@@ -8,7 +8,8 @@
import java.util.Set;
import seedu.address.commons.util.ToStringBuilder;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.clienttype.ClientType;
+import seedu.address.model.reminder.Reminder;
/**
* Represents a Person in the address book.
@@ -20,21 +21,26 @@ public class Person {
private final Name name;
private final Phone phone;
private final Email email;
+ private final Description description;
// Data fields
private final Address address;
- private final Set tags = new HashSet<>();
+ private final Set clientTypes = new HashSet<>();
+ private final Set reminders = new HashSet<>();
/**
* Every field must be present and not null.
*/
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
- requireAllNonNull(name, phone, email, address, tags);
+ public Person(Name name, Phone phone, Email email, Address address,
+ Set clientTypes, Description description, Set reminders) {
+ requireAllNonNull(name, phone, email, address, clientTypes, description);
this.name = name;
this.phone = phone;
this.email = email;
this.address = address;
- this.tags.addAll(tags);
+ this.clientTypes.addAll(clientTypes);
+ this.description = description;
+ this.reminders.addAll(reminders);
}
public Name getName() {
@@ -53,12 +59,23 @@ public Address getAddress() {
return address;
}
+ public Description getDescription() {
+ return description;
+ }
+
+ public Set getReminders() {
+ return Collections.unmodifiableSet(reminders);
+ }
+
/**
- * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
+ * Returns an immutable client type set, which throws {@code UnsupportedOperationException}
* if modification is attempted.
*/
- public Set getTags() {
- return Collections.unmodifiableSet(tags);
+ public Set getClientTypes() {
+ return Collections.unmodifiableSet(clientTypes);
+ }
+ public void addReminder(Reminder reminder) {
+ reminders.add(reminder);
}
/**
@@ -73,6 +90,9 @@ public boolean isSamePerson(Person otherPerson) {
return otherPerson != null
&& otherPerson.getName().equals(getName());
}
+ public void deleteReminder(Reminder reminder) {
+ reminders.remove(reminder);
+ }
/**
* Returns true if both persons have the same identity and data fields.
@@ -94,13 +114,15 @@ public boolean equals(Object other) {
&& phone.equals(otherPerson.phone)
&& email.equals(otherPerson.email)
&& address.equals(otherPerson.address)
- && tags.equals(otherPerson.tags);
+ && clientTypes.equals(otherPerson.clientTypes)
+ && description.equals(otherPerson.description)
+ && reminders.equals(otherPerson.reminders);
}
@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, address, clientTypes, description, reminders);
}
@Override
@@ -110,8 +132,9 @@ public String toString() {
.add("phone", phone)
.add("email", email)
.add("address", address)
- .add("tags", tags)
+ .add("clientTypes", clientTypes)
+ .add("description", description)
+ .add("reminders", reminders)
.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..cedf9b23989 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 should only contain numbers, and it should be 8 digits long";
+ public static final String VALIDATION_REGEX = "\\d{8}";
public final String value;
/**
diff --git a/src/main/java/seedu/address/model/person/PhoneBeginsWithKeywordPredicate.java b/src/main/java/seedu/address/model/person/PhoneBeginsWithKeywordPredicate.java
new file mode 100644
index 00000000000..b9b2dcbb034
--- /dev/null
+++ b/src/main/java/seedu/address/model/person/PhoneBeginsWithKeywordPredicate.java
@@ -0,0 +1,44 @@
+package seedu.address.model.person;
+
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Person}'s {@code Phone} matches any of the keywords given.
+ */
+public class PhoneBeginsWithKeywordPredicate implements Predicate {
+ private final String keyword;
+
+ public PhoneBeginsWithKeywordPredicate(String keyword) {
+ this.keyword = keyword;
+ }
+
+ @Override
+ public boolean test(Person person) {
+ if (keyword.isEmpty()) {
+ return false;
+ }
+ return person.getPhone().value.startsWith(keyword);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof PhoneBeginsWithKeywordPredicate)) {
+ return false;
+ }
+
+ PhoneBeginsWithKeywordPredicate otherPhoneBeginsWithKeywordPredicate = (PhoneBeginsWithKeywordPredicate) other;
+ return keyword.equals(otherPhoneBeginsWithKeywordPredicate.keyword);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("keyword", keyword).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java
index cc0a68d79f9..a8bacf7b94c 100644
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ b/src/main/java/seedu/address/model/person/UniquePersonList.java
@@ -5,6 +5,7 @@
import java.util.Iterator;
import java.util.List;
+import java.util.stream.Stream;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
@@ -27,6 +28,9 @@ public class UniquePersonList implements Iterable {
private final ObservableList internalList = FXCollections.observableArrayList();
private final ObservableList internalUnmodifiableList =
FXCollections.unmodifiableObservableList(internalList);
+ public Stream stream() {
+ return internalList.stream();
+ }
/**
* Returns true if the list contains an equivalent person as the given argument.
diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
index fa764426ca7..26ca466245c 100644
--- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
+++ b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
@@ -3,4 +3,8 @@
/**
* Signals that the operation is unable to find the specified person.
*/
-public class PersonNotFoundException extends RuntimeException {}
+public class PersonNotFoundException extends RuntimeException {
+ public PersonNotFoundException() {
+ super("Person not found!");
+ }
+}
diff --git a/src/main/java/seedu/address/model/reminder/Reminder.java b/src/main/java/seedu/address/model/reminder/Reminder.java
new file mode 100644
index 00000000000..b5d7867eeb4
--- /dev/null
+++ b/src/main/java/seedu/address/model/reminder/Reminder.java
@@ -0,0 +1,108 @@
+package seedu.address.model.reminder;
+import java.time.LocalDateTime;
+import java.util.Objects;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Represents a Reminder associated with a person in the address book.
+ * Guarantees: details are present and not null, field values are validated, immutable.
+ */
+public class Reminder {
+ private final String personName;
+ private final LocalDateTime dateTime;
+ private final ReminderDescription description;
+
+ /**
+ * Creates a Reminder with the specified person, date and time, and description.
+ *
+ * @param person the person associated with the reminder
+ * @param dateTime the date and time of the reminder
+ * @param description the description of the reminder
+ */
+ public Reminder(String person, LocalDateTime dateTime, ReminderDescription description) {
+ this.personName = Objects.requireNonNull(person, "Person name cannot be null");
+ this.dateTime = Objects.requireNonNull(dateTime, "DateTime cannot be null");
+ this.description = Objects.requireNonNull(description, "Description cannot be null");
+ }
+
+ public String getPersonName() {
+ return personName;
+ }
+
+ public LocalDateTime getDateTime() {
+ return dateTime;
+ }
+
+ public ReminderDescription getDescription() {
+ return description;
+ }
+
+ /**
+ * Returns true if both reminders are associated with the same person, date and time,
+ * and have the same description. This defines a stronger notion of equality between two reminders.
+ *
+ * @param other the other object to compare to
+ * @return true if both reminders are equal, false otherwise
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (!(other instanceof Reminder)) {
+ return false;
+ }
+
+ Reminder otherReminder = (Reminder) other;
+ return personName.equals(otherReminder.personName)
+ && dateTime.equals(otherReminder.dateTime)
+ && description.equals(otherReminder.description);
+ }
+
+ /**
+ * Checks if this reminder is the same as another reminder.
+ * Two reminders are considered the same if they have identical descriptions and times.
+ *
+ * @param otherReminder The other reminder to compare with.
+ * @return True if the reminders are the same, false otherwise.
+ */
+ public boolean isSameReminder(Reminder otherReminder) {
+ if (otherReminder == this) {
+ return true;
+ }
+
+ return otherReminder != null
+ && otherReminder.getDescription().equals(getDescription())
+ && otherReminder.getDateTime().equals(getDateTime());
+ }
+ @Override
+ public int hashCode() {
+ return Objects.hash(personName, dateTime, description);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("name", personName)
+ .add("Date and time", this.getFormattedDateTime())
+ .add("description", description)
+ .toString();
+ }
+
+ public Reminder getReminderWithFullName(String fullName) {
+ return new Reminder(fullName, this.dateTime, this.description);
+ }
+
+ /**
+ * Returns the formatted date and time string.
+ * @return formatted date and time string
+ */
+ public String getFormattedDateTime() {
+ String dateString = this.dateTime.toLocalDate().toString();
+ String timeString = this.dateTime.toLocalTime().toString();
+ return dateString + " " + timeString;
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/reminder/ReminderDescription.java b/src/main/java/seedu/address/model/reminder/ReminderDescription.java
new file mode 100644
index 00000000000..6482a2289fe
--- /dev/null
+++ b/src/main/java/seedu/address/model/reminder/ReminderDescription.java
@@ -0,0 +1,66 @@
+package seedu.address.model.reminder;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Description in the system.
+ * Guarantees: immutable; is valid as declared in {@link #VALIDATION_REGEX}
+ */
+public class ReminderDescription {
+ public static final String MESSAGE_CONSTRAINTS = "Reminder description cannot be empty or be more than "
+ + "300 characters";
+
+ // Allow printable characters excluding control characters
+ public static final String VALIDATION_REGEX = "^[\\p{Print}&&[^\\p{Cntrl}]]*$";
+
+ public static final int MAX_LENGTH = 300;
+ public static final int MIN_LENGTH = 1;
+
+ public final String description;
+
+ /**
+ * Constructs a {@code Description}.
+ *
+ * @param description A valid description.
+ */
+ public ReminderDescription(String description) {
+ requireNonNull(description);
+ checkArgument(isValidReminderDescription(description), MESSAGE_CONSTRAINTS);
+ this.description = description;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof ReminderDescription)) {
+ return false;
+ }
+
+ ReminderDescription otherDescription = (ReminderDescription) other;
+ return description.equals(otherDescription.description);
+ }
+
+ @Override
+ public int hashCode() {
+ return description.hashCode();
+ }
+
+ /**
+ * Format state as text for viewing.
+ */
+ public String toString() {
+ return '[' + description + ']';
+ }
+
+ /**
+ * Returns true if a given string is a valid description.
+ */
+ public static boolean isValidReminderDescription(String test) {
+ return test.matches(VALIDATION_REGEX)
+ && test.trim().length() <= MAX_LENGTH && test.trim().length() >= MIN_LENGTH;
+ }
+}
diff --git a/src/main/java/seedu/address/model/reminder/ReminderList.java b/src/main/java/seedu/address/model/reminder/ReminderList.java
new file mode 100644
index 00000000000..72b04bbe650
--- /dev/null
+++ b/src/main/java/seedu/address/model/reminder/ReminderList.java
@@ -0,0 +1,148 @@
+package seedu.address.model.reminder;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+
+/**
+ * A list of reminders that does not allow nulls.
+ * Supports a minimal set of list operations.
+ */
+public class ReminderList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList = FXCollections
+ .unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent reminder as the given argument.
+ *
+ * @param toCheck The reminder to check.
+ * @return True if the reminder is found in the list, false otherwise.
+ */
+ public boolean contains(Reminder toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameReminder);
+ }
+
+ /**
+ * Adds a reminder to the list.
+ *
+ * @param toAdd The reminder to add. Must not already exist in the list.
+ */
+ public void add(Reminder toAdd) {
+ requireNonNull(toAdd);
+ internalList.add(toAdd);
+ }
+
+ /**
+ * Replaces the given reminder {@code target} in the list with {@code editedReminder}.
+ *
+ * @param target The reminder to be replaced. Must exist in the list.
+ * @param editedReminder The reminder to replace {@code target} with.
+ * @throws ReminderNotFoundException If {@code target} is not found in the list.
+ */
+ public void setReminder(Reminder target, Reminder editedReminder) {
+ requireAllNonNull(target, editedReminder);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new ReminderNotFoundException();
+ }
+
+ internalList.set(index, editedReminder);
+ }
+
+ /**
+ * Removes the specified reminder from the list.
+ *
+ * @param toRemove The reminder to remove. Must exist in the list.
+ * @throws ReminderNotFoundException If the reminder is not found in the list.
+ */
+ public void remove(Reminder toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new ReminderNotFoundException();
+ }
+ }
+
+ /**
+ * Replaces the contents of this list with {@code replacement}.
+ *
+ * @param replacement The list to replace the current list with.
+ */
+ public void setReminders(ReminderList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ }
+
+ /**
+ * Replaces the contents of this list with {@code reminders}.
+ *
+ * @param reminders The list of reminders to set.
+ */
+ public void setReminders(List reminders) {
+ requireAllNonNull(reminders);
+ internalList.setAll(reminders);
+ }
+
+ /**
+ * Returns the backing list as an unmodifiable {@code ObservableList}.
+ *
+ * @return The unmodifiable observable list of reminders.
+ */
+ public ObservableList asUnmodifiableObservableList() {
+ return internalUnmodifiableList;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return internalList.iterator();
+ }
+
+ /**
+ * Checks if this list is equal to another object.
+ *
+ * @param other The object to compare with.
+ * @return True if the lists are equal, false otherwise.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof ReminderList)) {
+ return false;
+ }
+
+ ReminderList otherReminderList = (ReminderList) other;
+ return internalList.equals(otherReminderList.internalList);
+ }
+
+ /**
+ * Returns the hash code of the list.
+ *
+ * @return The hash code of the internal list.
+ */
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ /**
+ * Returns a string representation of the reminder list.
+ *
+ * @return A string representing the reminder list.
+ */
+ @Override
+ public String toString() {
+ return internalList.toString();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/reminder/ReminderNotFoundException.java b/src/main/java/seedu/address/model/reminder/ReminderNotFoundException.java
new file mode 100644
index 00000000000..26b28dabd12
--- /dev/null
+++ b/src/main/java/seedu/address/model/reminder/ReminderNotFoundException.java
@@ -0,0 +1,13 @@
+package seedu.address.model.reminder;
+
+/**
+ * Signals that the specified reminder could not be found.
+ */
+public class ReminderNotFoundException extends RuntimeException {
+ /**
+ * Constructs a {@code ReminderNotFoundException} with a default error message.
+ */
+ public ReminderNotFoundException() {
+ super("Reminder not found!");
+ }
+}
diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/address/model/tag/Tag.java
deleted file mode 100644
index f1a0d4e233b..00000000000
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package seedu.address.model.tag;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Tag in the address book.
- * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)}
- */
-public class Tag {
-
- public static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric";
- public static final String VALIDATION_REGEX = "\\p{Alnum}+";
-
- public final String tagName;
-
- /**
- * Constructs a {@code Tag}.
- *
- * @param tagName A valid tag name.
- */
- public Tag(String tagName) {
- requireNonNull(tagName);
- checkArgument(isValidTagName(tagName), MESSAGE_CONSTRAINTS);
- this.tagName = tagName;
- }
-
- /**
- * Returns true if a given string is a valid tag name.
- */
- public static boolean isValidTagName(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof Tag)) {
- return false;
- }
-
- Tag otherTag = (Tag) other;
- return tagName.equals(otherTag.tagName);
- }
-
- @Override
- public int hashCode() {
- return tagName.hashCode();
- }
-
- /**
- * Format state as text for viewing.
- */
- public String toString() {
- return '[' + tagName + ']';
- }
-
-}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
index 1806da4facf..d6eeb6ca815 100644
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java
@@ -1,60 +1,78 @@
package seedu.address.model.util;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ClientHub;
+import seedu.address.model.ReadOnlyClientHub;
+import seedu.address.model.clienttype.ClientType;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Description;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.reminder.Reminder;
/**
- * Contains utility methods for populating {@code AddressBook} with sample data.
+ * Contains utility methods for populating {@code ClientHub} with sample data.
*/
public class SampleDataUtil {
public static Person[] getSamplePersons() {
return new Person[] {
- new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"),
+ new Person(new Name("Ahmad Syuaib"), new Phone("87438807"), new Email("ahmadsyuaib@example.com"),
new Address("Blk 30 Geylang Street 29, #06-40"),
- getTagSet("friends")),
- new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"),
+ getClientTypeSet("Investment"), new Description("Only free on weekends"), Collections.EMPTY_SET),
+ new Person(new Name("Jeremy Sim"), new Phone("99272758"), new Email("jeremysim@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"),
+ getClientTypeSet("Investment", "Healthcare"), new Description("Likes to play basketball"),
+ Collections.EMPTY_SET),
+ new Person(new Name("Liu Rui"), new Phone("93210283"), new Email("liurui@example.com"),
new Address("Blk 11 Ang Mo Kio Street 74, #11-04"),
- getTagSet("neighbours")),
- new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"),
+ getClientTypeSet("Insurance Plan", "Savings"), new Description("Plans to retire early"),
+ Collections.EMPTY_SET),
+ new Person(new Name("Rubin Lin"), new Phone("91031282"), new Email("rubinlin@example.com"),
new Address("Blk 436 Serangoon Gardens Street 26, #16-43"),
- getTagSet("family")),
- new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"),
+ getClientTypeSet("Healthcare", "Savings"), new Description("Started a podcast"),
+ Collections.EMPTY_SET),
+ new Person(new Name("Harith Nurhisham"), new Phone("92492021"), new Email("harithnurhisham@example.com"),
new Address("Blk 47 Tampines Street 20, #17-35"),
- getTagSet("classmates")),
+ getClientTypeSet("Insurance Plan", "Investment"), new Description("Does not like to travel "
+ + "out of the east"), Collections.EMPTY_SET),
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"))
+ getClientTypeSet("Investment"), new Description("Recently married"), Collections.EMPTY_SET),
+ new Person(new Name("Sarah Lee"), new Phone("89732145"), new Email("sarahlee@example.com"),
+ new Address("Blk 38 Boon Lay Street 43, #32-03"),
+ getClientTypeSet("Healthcare", "Insurance Plan"),
+ new Description("Takes care of old parents"), Collections.EMPTY_SET),
};
}
- public static ReadOnlyAddressBook getSampleAddressBook() {
- AddressBook sampleAb = new AddressBook();
+ public static ReadOnlyClientHub getSampleClientHub() {
+ ClientHub sampleCh = new ClientHub();
for (Person samplePerson : getSamplePersons()) {
- sampleAb.addPerson(samplePerson);
+ sampleCh.addPerson(samplePerson);
}
- return sampleAb;
+ return sampleCh;
}
/**
- * Returns a tag set containing the list of strings given.
+ * Returns a client type set containing the list of strings given.
*/
- public static Set getTagSet(String... strings) {
+ public static Set getClientTypeSet(String... strings) {
return Arrays.stream(strings)
- .map(Tag::new)
+ .map(ClientType::new)
.collect(Collectors.toSet());
}
+ /**
+ * Returns a client type set containing the list of reminders given.
+ */
+ public static Set getReminderSet(Reminder... reminders) {
+ return Arrays.stream(reminders)
+ .collect(Collectors.toSet());
+ }
}
diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/seedu/address/storage/AddressBookStorage.java
deleted file mode 100644
index f2e015105ae..00000000000
--- a/src/main/java/seedu/address/storage/AddressBookStorage.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-
-import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.ReadOnlyAddressBook;
-
-/**
- * Represents a storage for {@link seedu.address.model.AddressBook}.
- */
-public interface AddressBookStorage {
-
- /**
- * Returns the file path of the data file.
- */
- Path getAddressBookFilePath();
-
- /**
- * Returns AddressBook data as a {@link ReadOnlyAddressBook}.
- * Returns {@code Optional.empty()} if storage file is not found.
- *
- * @throws DataLoadingException if loading the data from storage failed.
- */
- Optional readAddressBook() throws DataLoadingException;
-
- /**
- * @see #getAddressBookFilePath()
- */
- Optional readAddressBook(Path filePath) throws DataLoadingException;
-
- /**
- * Saves the given {@link ReadOnlyAddressBook} to the storage.
- * @param addressBook cannot be null.
- * @throws IOException if there was any problem writing to the file.
- */
- void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
-
- /**
- * @see #saveAddressBook(ReadOnlyAddressBook)
- */
- void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException;
-
-}
diff --git a/src/main/java/seedu/address/storage/ClientHubStorage.java b/src/main/java/seedu/address/storage/ClientHubStorage.java
new file mode 100644
index 00000000000..385dccca1fb
--- /dev/null
+++ b/src/main/java/seedu/address/storage/ClientHubStorage.java
@@ -0,0 +1,46 @@
+package seedu.address.storage;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import seedu.address.commons.exceptions.DataLoadingException;
+import seedu.address.model.ClientHub;
+import seedu.address.model.ReadOnlyClientHub;
+
+/**
+ * Represents a storage for {@link ClientHub}.
+ */
+public interface ClientHubStorage {
+
+ /**
+ * Returns the file path of the data file.
+ */
+ Path getClientHubFilePath();
+
+ /**
+ * Returns ClientHub data as a {@link ReadOnlyClientHub}.
+ * Returns {@code Optional.empty()} if storage file is not found.
+ *
+ * @throws DataLoadingException if loading the data from storage failed.
+ */
+ Optional readClientHub() throws DataLoadingException;
+
+ /**
+ * @see #getClientHubFilePath()
+ */
+ Optional readClientHub(Path filePath) throws DataLoadingException;
+
+ /**
+ * Saves the given {@link ReadOnlyClientHub} to the storage.
+ * @param clientHub cannot be null.
+ * @throws IOException if there was any problem writing to the file.
+ */
+ void saveClientHub(ReadOnlyClientHub clientHub) throws IOException;
+
+ /**
+ * @see #saveClientHub(ReadOnlyClientHub) (ReadOnlyClientHub)
+ */
+ void saveClientHub(ReadOnlyClientHub clientHub, Path filePath) throws IOException;
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedClientType.java b/src/main/java/seedu/address/storage/JsonAdaptedClientType.java
new file mode 100644
index 00000000000..8c3de694013
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedClientType.java
@@ -0,0 +1,48 @@
+package seedu.address.storage;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.clienttype.ClientType;
+
+/**
+ * Jackson-friendly version of {@link ClientType}.
+ */
+class JsonAdaptedClientType {
+
+ private final String clientTypeName;
+
+ /**
+ * Constructs a {@code JsonAdaptedclientType} with the given {@code clientTypeName}.
+ */
+ @JsonCreator
+ public JsonAdaptedClientType(String clientTypeName) {
+ this.clientTypeName = clientTypeName;
+ }
+
+ /**
+ * Converts a given {@code clientType} into this class for Jackson use.
+ */
+ public JsonAdaptedClientType(ClientType source) {
+ clientTypeName = source.clientTypeName;
+ }
+
+ @JsonValue
+ public String getClientTypeName() {
+ return clientTypeName;
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted client type object into the model's {@code clientType} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted client type.
+ */
+ public ClientType toModelType() throws IllegalValueException {
+ if (!ClientType.isValidClientTypeName(clientTypeName)) {
+ throw new IllegalValueException(ClientType.MESSAGE_CONSTRAINTS);
+ }
+ return new ClientType(clientTypeName);
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
index bd1ca0f56c8..b127333cf95 100644
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
@@ -10,12 +10,14 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.clienttype.ClientType;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Description;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.reminder.Reminder;
/**
* Jackson-friendly version of {@link Person}.
@@ -28,7 +30,9 @@ class JsonAdaptedPerson {
private final String phone;
private final String email;
private final String address;
- private final List tags = new ArrayList<>();
+ private final List clientTypes = new ArrayList<>();
+ private final String description;
+ private final List reminders = new ArrayList<>();
/**
* Constructs a {@code JsonAdaptedPerson} with the given person details.
@@ -36,13 +40,19 @@ class JsonAdaptedPerson {
@JsonCreator
public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
@JsonProperty("email") String email, @JsonProperty("address") String address,
- @JsonProperty("tags") List tags) {
+ @JsonProperty("clientTypes") List clientTypes,
+ @JsonProperty("description") String description,
+ @JsonProperty("reminders") List reminders) {
this.name = name;
this.phone = phone;
this.email = email;
this.address = address;
- if (tags != null) {
- this.tags.addAll(tags);
+ if (clientTypes != null) {
+ this.clientTypes.addAll(clientTypes);
+ }
+ this.description = description;
+ if (reminders != null) {
+ this.reminders.addAll(reminders);
}
}
@@ -54,8 +64,12 @@ public JsonAdaptedPerson(Person source) {
phone = source.getPhone().value;
email = source.getEmail().value;
address = source.getAddress().value;
- tags.addAll(source.getTags().stream()
- .map(JsonAdaptedTag::new)
+ clientTypes.addAll(source.getClientTypes().stream()
+ .map(JsonAdaptedClientType::new)
+ .collect(Collectors.toList()));
+ description = source.getDescription().description;
+ reminders.addAll(source.getReminders().stream()
+ .map(JsonAdaptedReminder::new)
.collect(Collectors.toList()));
}
@@ -65,9 +79,13 @@ 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());
+ final List personClientTypes = new ArrayList<>();
+ for (JsonAdaptedClientType clientType : clientTypes) {
+ personClientTypes.add(clientType.toModelType());
+ }
+ final List reminders = new ArrayList<>();
+ for (JsonAdaptedReminder reminder : this.reminders) {
+ reminders.add(reminder.toModelType());
}
if (name == null) {
@@ -102,8 +120,23 @@ public Person toModelType() throws IllegalValueException {
}
final Address modelAddress = new Address(address);
- final Set modelTags = new HashSet<>(personTags);
- return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags);
+ final Set modelClientTypes = new HashSet<>(personClientTypes);
+
+
+ if (description == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ Description.class.getSimpleName()));
+ }
+
+ if (!Description.isValidDescription(description)) {
+ throw new IllegalValueException(Description.MESSAGE_CONSTRAINTS);
+ }
+
+ final Description modelDescription = new Description(description);
+ final Set modelReminder = new HashSet<>(reminders);
+
+ return new Person(modelName, modelPhone, modelEmail, modelAddress, modelClientTypes, modelDescription,
+ modelReminder);
}
}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedReminder.java b/src/main/java/seedu/address/storage/JsonAdaptedReminder.java
new file mode 100644
index 00000000000..a08ab857abb
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedReminder.java
@@ -0,0 +1,72 @@
+package seedu.address.storage;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.reminder.Reminder;
+import seedu.address.model.reminder.ReminderDescription;
+
+/**
+ * Jackson-friendly version of {@link Reminder}.
+ */
+class JsonAdaptedReminder {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Reminder's %s field is missing!";
+ private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
+ private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT);
+ private final String personName;
+ private final String dateTime;
+ private final String reminderDescription;
+
+ /**
+ * Constructs a {@code JsonAdaptedReminder} with the given reminder details.
+ */
+ @JsonCreator
+ public JsonAdaptedReminder(@JsonProperty("personName") String personName, @JsonProperty("dateTime") String dateTime,
+ @JsonProperty("reminderDescription") String reminderDescription) {
+ this.personName = personName;
+ this.dateTime = dateTime;
+ this.reminderDescription = reminderDescription;
+ }
+
+ /**
+ * Converts a given {@code Reminder} into this class for Jackson use.
+ */
+ public JsonAdaptedReminder(Reminder source) {
+ personName = source.getPersonName();
+ dateTime = source.getDateTime().format(formatter);
+ reminderDescription = source.getDescription().description;
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted reminder object into the model's {@code Reminder} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted reminder.
+ */
+ public Reminder toModelType() throws IllegalValueException {
+ if (dateTime == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, "DateTime"));
+ }
+
+ LocalDateTime modelDateTime;
+ try {
+ modelDateTime = LocalDateTime.parse(dateTime, formatter);
+ } catch (DateTimeParseException e) {
+ throw new IllegalValueException("DateTime must be in format: " + DATE_TIME_FORMAT);
+ }
+
+ if (reminderDescription == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, "ReminderDescription"));
+ }
+ if (!ReminderDescription.isValidReminderDescription(reminderDescription)) {
+ throw new IllegalValueException(ReminderDescription.MESSAGE_CONSTRAINTS);
+ }
+
+ return new Reminder(personName, modelDateTime, new ReminderDescription(reminderDescription));
+ }
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/seedu/address/storage/JsonAdaptedTag.java
deleted file mode 100644
index 0df22bdb754..00000000000
--- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package seedu.address.storage;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonValue;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.tag.Tag;
-
-/**
- * Jackson-friendly version of {@link Tag}.
- */
-class JsonAdaptedTag {
-
- private final String tagName;
-
- /**
- * Constructs a {@code JsonAdaptedTag} with the given {@code tagName}.
- */
- @JsonCreator
- public JsonAdaptedTag(String tagName) {
- this.tagName = tagName;
- }
-
- /**
- * Converts a given {@code Tag} into this class for Jackson use.
- */
- public JsonAdaptedTag(Tag source) {
- tagName = source.tagName;
- }
-
- @JsonValue
- public String getTagName() {
- return tagName;
- }
-
- /**
- * Converts this Jackson-friendly adapted tag object into the model's {@code Tag} object.
- *
- * @throws IllegalValueException if there were any data constraints violated in the adapted tag.
- */
- public Tag toModelType() throws IllegalValueException {
- if (!Tag.isValidTagName(tagName)) {
- throw new IllegalValueException(Tag.MESSAGE_CONSTRAINTS);
- }
- return new Tag(tagName);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/seedu/address/storage/JsonClientHubStorage.java
similarity index 50%
rename from src/main/java/seedu/address/storage/JsonAddressBookStorage.java
rename to src/main/java/seedu/address/storage/JsonClientHubStorage.java
index 41e06f264e1..9353146b478 100644
--- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
+++ b/src/main/java/seedu/address/storage/JsonClientHubStorage.java
@@ -12,47 +12,47 @@
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.commons.util.FileUtil;
import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyClientHub;
/**
- * A class to access AddressBook data stored as a json file on the hard disk.
+ * A class to access ClientHub data stored as a json file on the hard disk.
*/
-public class JsonAddressBookStorage implements AddressBookStorage {
+public class JsonClientHubStorage implements ClientHubStorage {
- private static final Logger logger = LogsCenter.getLogger(JsonAddressBookStorage.class);
+ private static final Logger logger = LogsCenter.getLogger(JsonClientHubStorage.class);
private Path filePath;
- public JsonAddressBookStorage(Path filePath) {
+ public JsonClientHubStorage(Path filePath) {
this.filePath = filePath;
}
- public Path getAddressBookFilePath() {
+ public Path getClientHubFilePath() {
return filePath;
}
@Override
- public Optional readAddressBook() throws DataLoadingException {
- return readAddressBook(filePath);
+ public Optional readClientHub() throws DataLoadingException {
+ return readClientHub(filePath);
}
/**
- * Similar to {@link #readAddressBook()}.
+ * Similar to {@link #readClientHub()}.
*
* @param filePath location of the data. Cannot be null.
* @throws DataLoadingException if loading the data from storage failed.
*/
- public Optional readAddressBook(Path filePath) throws DataLoadingException {
+ public Optional readClientHub(Path filePath) throws DataLoadingException {
requireNonNull(filePath);
- Optional jsonAddressBook = JsonUtil.readJsonFile(
- filePath, JsonSerializableAddressBook.class);
- if (!jsonAddressBook.isPresent()) {
+ Optional jsonClientHub = JsonUtil.readJsonFile(
+ filePath, JsonSerializableClientHub.class);
+ if (!jsonClientHub.isPresent()) {
return Optional.empty();
}
try {
- return Optional.of(jsonAddressBook.get().toModelType());
+ return Optional.of(jsonClientHub.get().toModelType());
} catch (IllegalValueException ive) {
logger.info("Illegal values found in " + filePath + ": " + ive.getMessage());
throw new DataLoadingException(ive);
@@ -60,21 +60,21 @@ public Optional readAddressBook(Path filePath) throws DataL
}
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, filePath);
+ public void saveClientHub(ReadOnlyClientHub clientHub) throws IOException {
+ saveClientHub(clientHub, filePath);
}
/**
- * Similar to {@link #saveAddressBook(ReadOnlyAddressBook)}.
+ * Similar to {@link #saveClientHub(ReadOnlyClientHub)}.
*
* @param filePath location of the data. Cannot be null.
*/
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
- requireNonNull(addressBook);
+ public void saveClientHub(ReadOnlyClientHub clientHub, Path filePath) throws IOException {
+ requireNonNull(clientHub);
requireNonNull(filePath);
FileUtil.createIfMissing(filePath);
- JsonUtil.saveJsonFile(new JsonSerializableAddressBook(addressBook), filePath);
+ JsonUtil.saveJsonFile(new JsonSerializableClientHub(clientHub), filePath);
}
}
diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
deleted file mode 100644
index 5efd834091d..00000000000
--- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonRootName;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * An Immutable AddressBook that is serializable to JSON format.
- */
-@JsonRootName(value = "addressbook")
-class JsonSerializableAddressBook {
-
- public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
-
- private final List persons = new ArrayList<>();
-
- /**
- * Constructs a {@code JsonSerializableAddressBook} with the given persons.
- */
- @JsonCreator
- public JsonSerializableAddressBook(@JsonProperty("persons") List persons) {
- this.persons.addAll(persons);
- }
-
- /**
- * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use.
- *
- * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}.
- */
- public JsonSerializableAddressBook(ReadOnlyAddressBook source) {
- persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList()));
- }
-
- /**
- * Converts this address book into the model's {@code AddressBook} object.
- *
- * @throws IllegalValueException if there were any data constraints violated.
- */
- public AddressBook toModelType() throws IllegalValueException {
- AddressBook addressBook = new AddressBook();
- for (JsonAdaptedPerson jsonAdaptedPerson : persons) {
- Person person = jsonAdaptedPerson.toModelType();
- if (addressBook.hasPerson(person)) {
- throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON);
- }
- addressBook.addPerson(person);
- }
- return addressBook;
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonSerializableClientHub.java b/src/main/java/seedu/address/storage/JsonSerializableClientHub.java
new file mode 100644
index 00000000000..577bc16f9c5
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonSerializableClientHub.java
@@ -0,0 +1,82 @@
+package seedu.address.storage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.ClientHub;
+import seedu.address.model.ReadOnlyClientHub;
+import seedu.address.model.person.Person;
+import seedu.address.model.reminder.Reminder;
+
+/**
+ * An Immutable ClientHub that is serializable to JSON format.
+ */
+@JsonRootName(value = "clienthub")
+class JsonSerializableClientHub {
+
+ public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
+ public static final String MESSAGE_DUPLICATE_REMINDER = "Reminders list contains duplicate reminder(s).";
+
+ private final List persons = new ArrayList<>();
+ private final List reminders = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonSerializableClientHub} with the given persons and reminders.
+ */
+ @JsonCreator
+ public JsonSerializableClientHub(
+ @JsonProperty("persons") List persons,
+ @JsonProperty("reminders") List reminders) {
+ if (persons != null) {
+ this.persons.addAll(persons);
+ }
+ if (reminders != null) {
+ this.reminders.addAll(reminders);
+ }
+ }
+
+ /**
+ * Converts a given {@code ReadOnlyClientHub} into this class for Jackson use.
+ *
+ * @param source future changes to this will not affect the created {@code JsonSerializableClientHub}.
+ */
+ public JsonSerializableClientHub(ReadOnlyClientHub source) {
+ persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList()));
+ reminders.addAll(source.getReminderList().stream().map(JsonAdaptedReminder::new).collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this client hub into the model's {@code ClientHub} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated.
+ */
+ public ClientHub toModelType() throws IllegalValueException {
+ ClientHub clientHub = new ClientHub();
+
+ // Add persons to the ClientHub, checking for duplicates
+ for (JsonAdaptedPerson jsonAdaptedPerson : persons) {
+ Person person = jsonAdaptedPerson.toModelType();
+ if (clientHub.hasPerson(person)) {
+ throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON);
+ }
+ clientHub.addPerson(person);
+ }
+
+ // Add reminders to the ClientHub, checking for duplicates
+ for (JsonAdaptedReminder jsonAdaptedReminder : reminders) {
+ Reminder reminder = jsonAdaptedReminder.toModelType();
+ if (clientHub.hasReminder(reminder)) {
+ throw new IllegalValueException(MESSAGE_DUPLICATE_REMINDER);
+ }
+ clientHub.addReminder(reminder);
+ }
+
+ return clientHub;
+ }
+}
diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java
index 9fba0c7a1d6..45c898a3af6 100644
--- a/src/main/java/seedu/address/storage/Storage.java
+++ b/src/main/java/seedu/address/storage/Storage.java
@@ -5,14 +5,14 @@
import java.util.Optional;
import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyClientHub;
import seedu.address.model.ReadOnlyUserPrefs;
import seedu.address.model.UserPrefs;
/**
* API of the Storage component
*/
-public interface Storage extends AddressBookStorage, UserPrefsStorage {
+public interface Storage extends ClientHubStorage, UserPrefsStorage {
@Override
Optional readUserPrefs() throws DataLoadingException;
@@ -21,12 +21,12 @@ public interface Storage extends AddressBookStorage, UserPrefsStorage {
void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException;
@Override
- Path getAddressBookFilePath();
+ Path getClientHubFilePath();
@Override
- Optional readAddressBook() throws DataLoadingException;
+ Optional readClientHub() throws DataLoadingException;
@Override
- void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
+ void saveClientHub(ReadOnlyClientHub clientHub) throws IOException;
}
diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java
index 8b84a9024d5..3e5e4210222 100644
--- a/src/main/java/seedu/address/storage/StorageManager.java
+++ b/src/main/java/seedu/address/storage/StorageManager.java
@@ -7,24 +7,24 @@
import seedu.address.commons.core.LogsCenter;
import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyClientHub;
import seedu.address.model.ReadOnlyUserPrefs;
import seedu.address.model.UserPrefs;
/**
- * Manages storage of AddressBook data in local storage.
+ * Manages storage of ClientHub data in local storage.
*/
public class StorageManager implements Storage {
private static final Logger logger = LogsCenter.getLogger(StorageManager.class);
- private AddressBookStorage addressBookStorage;
+ private ClientHubStorage clientHubStorage;
private UserPrefsStorage userPrefsStorage;
/**
- * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}.
+ * Creates a {@code StorageManager} with the given {@code ClientHubStorage} and {@code UserPrefStorage}.
*/
- public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) {
- this.addressBookStorage = addressBookStorage;
+ public StorageManager(ClientHubStorage clientHubStorage, UserPrefsStorage userPrefsStorage) {
+ this.clientHubStorage = clientHubStorage;
this.userPrefsStorage = userPrefsStorage;
}
@@ -46,33 +46,33 @@ public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException {
}
- // ================ AddressBook methods ==============================
+ // ================ ClientHub methods ==============================
@Override
- public Path getAddressBookFilePath() {
- return addressBookStorage.getAddressBookFilePath();
+ public Path getClientHubFilePath() {
+ return clientHubStorage.getClientHubFilePath();
}
@Override
- public Optional readAddressBook() throws DataLoadingException {
- return readAddressBook(addressBookStorage.getAddressBookFilePath());
+ public Optional readClientHub() throws DataLoadingException {
+ return readClientHub(clientHubStorage.getClientHubFilePath());
}
@Override
- public Optional readAddressBook(Path filePath) throws DataLoadingException {
+ public Optional readClientHub(Path filePath) throws DataLoadingException {
logger.fine("Attempting to read data from file: " + filePath);
- return addressBookStorage.readAddressBook(filePath);
+ return clientHubStorage.readClientHub(filePath);
}
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, addressBookStorage.getAddressBookFilePath());
+ public void saveClientHub(ReadOnlyClientHub clientHub) throws IOException {
+ saveClientHub(clientHub, clientHubStorage.getClientHubFilePath());
}
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
+ public void saveClientHub(ReadOnlyClientHub clientHub, Path filePath) throws IOException {
logger.fine("Attempting to write to data file: " + filePath);
- addressBookStorage.saveAddressBook(addressBook, filePath);
+ clientHubStorage.saveClientHub(clientHub, filePath);
}
}
diff --git a/src/main/java/seedu/address/ui/CommandBox.java b/src/main/java/seedu/address/ui/CommandBox.java
index 9e75478664b..6dd771a5037 100644
--- a/src/main/java/seedu/address/ui/CommandBox.java
+++ b/src/main/java/seedu/address/ui/CommandBox.java
@@ -1,8 +1,12 @@
package seedu.address.ui;
+import java.util.ArrayList;
+import java.util.List;
+
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
+import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Region;
import seedu.address.logic.commands.CommandResult;
import seedu.address.logic.commands.exceptions.CommandException;
@@ -18,6 +22,10 @@ public class CommandBox extends UiPart {
private final CommandExecutor commandExecutor;
+ // Attributes for command history
+ private int commandHistoryIndex = -1;
+ private List commandHistory = new ArrayList<>();
+
@FXML
private TextField commandTextField;
@@ -27,10 +35,54 @@ public class CommandBox extends UiPart {
public CommandBox(CommandExecutor commandExecutor) {
super(FXML);
this.commandExecutor = commandExecutor;
+
+ // Listens for key presses on the command box.
+ commandTextField.setOnKeyPressed(this::handleKeyPress);
// calls #setStyleToDefault() whenever there is a change to the text of the command box.
commandTextField.textProperty().addListener((unused1, unused2, unused3) -> setStyleToDefault());
}
+ private void handleKeyPress(KeyEvent keyEvent) {
+ switch (keyEvent.getCode()) {
+ case UP:
+ navigateToPreviousCommand();
+ keyEvent.consume();
+ break;
+ case DOWN:
+ navigateToNextCommand();
+ keyEvent.consume();
+ break;
+ default:
+ // do nothing
+ }
+ }
+
+ private void navigateToPreviousCommand() {
+ if (commandHistoryIndex > 0) {
+ commandHistoryIndex--;
+ commandTextField.setText(commandHistory.get(commandHistoryIndex));
+ commandTextField.positionCaret(commandTextField.getText().length());
+ } else if (commandHistoryIndex == 0) {
+ commandTextField.setText(commandHistory.get(0));
+ commandTextField.positionCaret(commandTextField.getText().length());
+ } else {
+ commandTextField.clear();
+ }
+ }
+
+ private void navigateToNextCommand() {
+ if (commandHistoryIndex < commandHistory.size() - 1) {
+ commandHistoryIndex++;
+ commandTextField.setText(commandHistory.get(commandHistoryIndex));
+ commandTextField.positionCaret(commandTextField.getText().length());
+ } else if (commandHistoryIndex == commandHistory.size() - 1) {
+ commandHistoryIndex = commandHistory.size();
+ commandTextField.clear();
+ } else {
+ commandTextField.clear();
+ }
+ }
+
/**
* Handles the Enter button pressed event.
*/
@@ -40,12 +92,17 @@ private void handleCommandEntered() {
if (commandText.equals("")) {
return;
}
-
try {
commandExecutor.execute(commandText);
commandTextField.setText("");
+
} catch (CommandException | ParseException e) {
setStyleToIndicateCommandFailure();
+
+ } finally {
+ // Update command history
+ commandHistory.add(commandText);
+ commandHistoryIndex = commandHistory.size();
}
}
diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/address/ui/HelpWindow.java
index 3f16b2fcf26..aea3eb0b8e0 100644
--- a/src/main/java/seedu/address/ui/HelpWindow.java
+++ b/src/main/java/seedu/address/ui/HelpWindow.java
@@ -15,9 +15,50 @@
*/
public class HelpWindow extends UiPart {
- public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html";
- public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL;
+ public static final String USERGUIDE_URL = "https://ay2425s1-cs2103t-f10-1.github.io/tp/UserGuide.html";
+ public static final String USERGUIDE_REF = "For more info, refer to the user guide: \n" + USERGUIDE_URL;
+ public static final String ADD_HELP_HEADER = "Add contacts: ";
+ public static final String ADD_HELP_1 = "add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS d/DESCRIPTION [c/CLIENT_TYPE]";
+ public static final String ADD_HELP_2 = "a n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS d/DESCRIPTION [c/CLIENT_TYPE]";
+ public static final String LIST_HELP_HEADER = "List all contacts in ClientHub: ";
+ public static final String LIST_HELP = "list";
+ public static final String EDIT_HELP_HEADER = "Edit contacts: ";
+ public static final String EDIT_HELP = "edit INDEX n/NAME p/PHONE e/EMAIL a/ADDRESS d/DESCRIPTION c/CLIENT_TYPE";
+ public static final String DELETE_HELP_HEADER = "Delete contacts by name: ";
+ public static final String DELETE_HELP_1 = "delete NAME";
+ public static final String DELETE_HELP_2 = "d NAME";
+ public static final String DELETE_HELP_3 = "delete NAME/";
+ public static final String CLEAR_HELP_HEADER = "Delete all contacts from ClientHub: ";
+ public static final String CLEAR_HELP = "clear";
+ public static final String FN_HELP_HEADER = "Find contacts by name: ";
+ public static final String FN_HELP_1 = "find n/NAME";
+ public static final String FN_HELP_2 = "fn NAME";
+ public static final String FP_HELP_HEADER = "Find contacts by phone number: ";
+ public static final String FP_HELP_1 = "find p/PHONE";
+ public static final String FP_HELP_2 = "fp PHONE";
+ public static final String FA_HELP_HEADER = "Find contacts by address: ";
+ public static final String FA_HELP_1 = "find a/ADDRESS";
+ public static final String FA_HELP_2 = "fa ADDRESS";
+ public static final String FC_HELP_HEADER = "Find contacts by Client Type: ";
+ public static final String FC_HELP_1 = "find c/CLIENT_TYPE";
+ public static final String FC_HELP_2 = "fc CLIENT_TYPE";
+ public static final String SORT_HELP_HEADER = "Sort contacts by name: ";
+ public static final String SORT_HELP = "sort";
+ public static final String VIEW_HELP_HEADER = "View a contact's full information: ";
+ public static final String VIEW_HELP_1 = "view NAME";
+ public static final String VIEW_HELP_2 = "v NAME";
+ public static final String RA_HELP_HEADER = "Add a reminder for a contact: ";
+ public static final String RA_HELP_1 = "radd n/NAME dt/DATE and TIME d/DESCRIPTION";
+ public static final String RA_HELP_2 = "ra n/NAME dt/DATE and TIME d/DESCRIPTION";
+ public static final String RE_HELP_HEADER = "Edit a reminder for a contact: ";
+ public static final String RE_HELP_1 = "redit INDEX dt/DATE and TIME d/DESCRIPTION";
+ public static final String RE_HELP_2 = "re INDEX dt/DATE and TIME d/DESCRIPTION";
+ public static final String RD_HELP_HEADER = "Delete a reminder for a contact: ";
+ public static final String RD_HELP_1 = "rdelete INDEX";
+ public static final String RD_HELP_2 = "rd INDEX";
+ public static final String EXIT_HELP_HEADER = "Exit and close ClientHub: ";
+ public static final String EXIT_HELP = "exit";
private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
private static final String FXML = "HelpWindow.fxml";
@@ -27,6 +68,129 @@ public class HelpWindow extends UiPart {
@FXML
private Label helpMessage;
+ @FXML
+ private Label addHelpHeader;
+
+ @FXML
+ private Label addHelp1;
+
+ @FXML
+ private Label addHelp2;
+
+ @FXML
+ private Label listHelpHeader;
+
+ @FXML
+ private Label listHelp;
+
+ @FXML
+ private Label editHelpHeader;
+
+ @FXML
+ private Label editHelp;
+
+ @FXML
+ private Label deleteHelpHeader;
+
+ @FXML
+ private Label deleteHelp1;
+
+ @FXML
+ private Label deleteHelp2;
+
+ @FXML
+ private Label deleteHelp3;
+
+ @FXML
+ private Label clearHelpHeader;
+
+ @FXML
+ private Label clearHelp;
+
+ @FXML
+ private Label fnHelpHeader;
+
+ @FXML
+ private Label fnHelp1;
+
+ @FXML
+ private Label fnHelp2;
+
+ @FXML
+ private Label fpHelpHeader;
+
+ @FXML
+ private Label fpHelp1;
+
+ @FXML
+ private Label fpHelp2;
+
+ @FXML
+ private Label faHelpHeader;
+
+ @FXML
+ private Label faHelp1;
+
+ @FXML
+ private Label faHelp2;
+
+ @FXML
+ private Label fcHelpHeader;
+
+ @FXML
+ private Label fcHelp1;
+
+ @FXML
+ private Label fcHelp2;
+
+ @FXML
+ private Label sortHelpHeader;
+
+ @FXML
+ private Label sortHelp;
+
+ @FXML
+ private Label viewHelpHeader;
+
+ @FXML
+ private Label viewHelp1;
+
+ @FXML
+ private Label viewHelp2;
+
+ @FXML
+ private Label raHelpHeader;
+
+ @FXML
+ private Label raHelp1;
+
+ @FXML
+ private Label raHelp2;
+
+ @FXML
+ private Label reHelpHeader;
+
+ @FXML
+ private Label reHelp1;
+
+ @FXML
+ private Label reHelp2;
+
+ @FXML
+ private Label rdHelpHeader;
+
+ @FXML
+ private Label rdHelp1;
+
+ @FXML
+ private Label rdHelp2;
+
+ @FXML
+ private Label exitHelpHeader;
+
+ @FXML
+ private Label exitHelp;
+
/**
* Creates a new HelpWindow.
*
@@ -34,7 +198,50 @@ public class HelpWindow extends UiPart {
*/
public HelpWindow(Stage root) {
super(FXML, root);
- helpMessage.setText(HELP_MESSAGE);
+ helpMessage.setText(USERGUIDE_REF);
+
+ addHelpHeader.setText(ADD_HELP_HEADER);
+ listHelpHeader.setText(LIST_HELP_HEADER);
+ editHelpHeader.setText(EDIT_HELP_HEADER);
+ deleteHelpHeader.setText(DELETE_HELP_HEADER);
+ clearHelpHeader.setText(CLEAR_HELP_HEADER);
+ fnHelpHeader.setText(FN_HELP_HEADER);
+ fpHelpHeader.setText(FP_HELP_HEADER);
+ faHelpHeader.setText(FA_HELP_HEADER);
+ fcHelpHeader.setText(FC_HELP_HEADER);
+ sortHelpHeader.setText(SORT_HELP_HEADER);
+ viewHelpHeader.setText(VIEW_HELP_HEADER);
+ raHelpHeader.setText(RA_HELP_HEADER);
+ reHelpHeader.setText(RE_HELP_HEADER);
+ rdHelpHeader.setText(RD_HELP_HEADER);
+ exitHelpHeader.setText(EXIT_HELP_HEADER);
+
+ addHelp1.setText(ADD_HELP_1);
+ addHelp2.setText(ADD_HELP_2);
+ listHelp.setText(LIST_HELP);
+ editHelp.setText(EDIT_HELP);
+ deleteHelp1.setText(DELETE_HELP_1);
+ deleteHelp2.setText(DELETE_HELP_2);
+ deleteHelp3.setText(DELETE_HELP_3);
+ clearHelp.setText(CLEAR_HELP);
+ fnHelp1.setText(FN_HELP_1);
+ fnHelp2.setText(FN_HELP_2);
+ fpHelp1.setText(FP_HELP_1);
+ fpHelp2.setText(FP_HELP_2);
+ faHelp1.setText(FA_HELP_1);
+ faHelp2.setText(FA_HELP_2);
+ fcHelp1.setText(FC_HELP_1);
+ fcHelp2.setText(FC_HELP_2);
+ sortHelp.setText(SORT_HELP);
+ viewHelp1.setText(VIEW_HELP_1);
+ viewHelp2.setText(VIEW_HELP_2);
+ raHelp1.setText(RA_HELP_1);
+ raHelp2.setText(RA_HELP_2);
+ reHelp1.setText(RE_HELP_1);
+ reHelp2.setText(RE_HELP_2);
+ rdHelp1.setText(RD_HELP_1);
+ rdHelp2.setText(RD_HELP_2);
+ exitHelp.setText(EXIT_HELP);
}
/**
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java
index 79e74ef37c0..7a8122d3121 100644
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ b/src/main/java/seedu/address/ui/MainWindow.java
@@ -17,6 +17,7 @@
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.logic.parser.exceptions.ParseException;
+
/**
* The Main Window. Provides the basic application layout containing
* a menu bar and space where other JavaFX elements can be placed.
@@ -34,6 +35,8 @@ public class MainWindow extends UiPart {
private PersonListPanel personListPanel;
private ResultDisplay resultDisplay;
private HelpWindow helpWindow;
+ private ViewPersonWindow viewPersonWindow;
+ private ReminderListPanel reminderListPanel;
@FXML
private StackPane commandBoxPlaceholder;
@@ -50,6 +53,9 @@ public class MainWindow extends UiPart {
@FXML
private StackPane statusbarPlaceholder;
+ @FXML
+ private StackPane reminderListPanelPlaceholder;
+
/**
* Creates a {@code MainWindow} with the given {@code Stage} and {@code Logic}.
*/
@@ -65,6 +71,7 @@ public MainWindow(Stage primaryStage, Logic logic) {
setAccelerators();
+ // Initialise windows
helpWindow = new HelpWindow();
}
@@ -110,17 +117,27 @@ private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) {
* Fills up all the placeholders of this window.
*/
void fillInnerParts() {
- personListPanel = new PersonListPanel(logic.getFilteredPersonList());
+ // initialise person list panel
+ personListPanel = new PersonListPanel(logic.getPersonList());
personListPanelPlaceholder.getChildren().add(personListPanel.getRoot());
+ // initialise result display
resultDisplay = new ResultDisplay();
resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot());
- StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getAddressBookFilePath());
+ // initialise reminder list panel
+ reminderListPanel = new ReminderListPanel(logic.getReminderList());
+ reminderListPanelPlaceholder.getChildren().add(reminderListPanel.getRoot());
+
+ // initialise status bar
+ StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getClientHubFilePath());
statusbarPlaceholder.getChildren().add(statusBarFooter.getRoot());
+ // initialise command box
CommandBox commandBox = new CommandBox(this::executeCommand);
commandBoxPlaceholder.getChildren().add(commandBox.getRoot());
+
+
}
/**
@@ -160,9 +177,25 @@ private void handleExit() {
(int) primaryStage.getX(), (int) primaryStage.getY());
logic.setGuiSettings(guiSettings);
helpWindow.hide();
+
+ // If open, close the view person window
+ if (viewPersonWindow != null) {
+ viewPersonWindow.hide();
+ }
+
primaryStage.hide();
}
+ @FXML
+ private void handleView() {
+ viewPersonWindow = new ViewPersonWindow(logic.getPersonList());
+ if (!viewPersonWindow.isViewShowing()) {
+ viewPersonWindow.show();
+ } else {
+ viewPersonWindow.focus();
+ }
+ }
+
public PersonListPanel getPersonListPanel() {
return personListPanel;
}
@@ -182,6 +215,10 @@ private CommandResult executeCommand(String commandText) throws CommandException
handleHelp();
}
+ if (commandResult.isShowView()) {
+ handleView();
+ }
+
if (commandResult.isExit()) {
handleExit();
}
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
index 094c42cda82..f41ad3f21c6 100644
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ b/src/main/java/seedu/address/ui/PersonCard.java
@@ -39,7 +39,7 @@ public class PersonCard extends UiPart {
@FXML
private Label email;
@FXML
- private FlowPane tags;
+ private FlowPane clientTypes;
/**
* Creates a {@code PersonCode} with the given {@code Person} and index to display.
@@ -52,8 +52,8 @@ public PersonCard(Person person, int displayedIndex) {
phone.setText(person.getPhone().value);
address.setText(person.getAddress().value);
email.setText(person.getEmail().value);
- person.getTags().stream()
- .sorted(Comparator.comparing(tag -> tag.tagName))
- .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+ person.getClientTypes().stream()
+ .sorted(Comparator.comparing(clientType -> clientType.clientTypeName))
+ .forEach(clientType -> clientTypes.getChildren().add(new Label(clientType.clientTypeName)));
}
}
diff --git a/src/main/java/seedu/address/ui/ReminderCard.java b/src/main/java/seedu/address/ui/ReminderCard.java
new file mode 100644
index 00000000000..33b19114483
--- /dev/null
+++ b/src/main/java/seedu/address/ui/ReminderCard.java
@@ -0,0 +1,63 @@
+package seedu.address.ui;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import seedu.address.model.reminder.Reminder;
+
+/**
+ * An UI component that displays information of a {@code Reminder}.
+ */
+public class ReminderCard extends UiPart {
+
+ private static final String FXML = "ReminderCard.fxml";
+
+ public final Reminder reminder;
+
+ @FXML
+ private HBox reminderCardPane;
+ @FXML
+ private Label id;
+ @FXML
+ private Label personName;
+ @FXML
+ private Label description;
+ @FXML
+ private Label time;
+ @FXML
+ private Label date;
+
+ /**
+ * Creates a {@code ReminderCard} with dummy data using the given index.
+ */
+ public ReminderCard(Reminder reminder, int displayedIndex) {
+ super(FXML);
+ this.reminder = reminder;
+ id.setText(displayedIndex + ". ");
+ personName.setText(reminder.getPersonName());
+ description.setText(reminder.getDescription().description);
+
+ // Creates a more readable format for the date and time
+ String dateString = reminder.getDateTime().toLocalDate().toString(); // "2021-12-21"
+ String timeString = reminder.getDateTime().toLocalTime().toString(); // "23:59:00"
+ time.setText(timeString);
+ date.setText(dateString);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof ReminderCard)) {
+ return false;
+ }
+
+ ReminderCard card = (ReminderCard) other;
+ return id.getText().equals(card.id.getText())
+ && personName.getText().equals(card.personName.getText())
+ && description.getText().equals(card.description.getText());
+ }
+}
diff --git a/src/main/java/seedu/address/ui/ReminderListPanel.java b/src/main/java/seedu/address/ui/ReminderListPanel.java
new file mode 100644
index 00000000000..010fd12a514
--- /dev/null
+++ b/src/main/java/seedu/address/ui/ReminderListPanel.java
@@ -0,0 +1,49 @@
+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.reminder.Reminder;
+
+/**
+ * Panel containing the list of reminders.
+ */
+public class ReminderListPanel extends UiPart {
+ private static final String FXML = "ReminderListPanel.fxml";
+ private final Logger logger = LogsCenter.getLogger(ReminderListPanel.class);
+
+ @FXML
+ private ListView reminderListView;
+
+ /**
+ * Creates a {@code ReminderListPanel} with the given {@code ObservableList}.
+ */
+ public ReminderListPanel(ObservableList reminderList) {
+ super(FXML);
+ reminderListView.setItems(reminderList);
+ reminderListView.setCellFactory(listView -> new ReminderListViewCell());
+
+ }
+
+ /**
+ * Custom {@code ListCell} that displays the graphics of a {@code Reminder} using a {@code ReminderCard}.
+ */
+ class ReminderListViewCell extends ListCell {
+ @Override
+ protected void updateItem(Reminder reminder, boolean empty) {
+ super.updateItem(reminder, empty);
+
+ if (empty || reminder == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new ReminderCard(reminder, getIndex() + 1).getRoot());
+ }
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/ui/ViewPersonWindow.java b/src/main/java/seedu/address/ui/ViewPersonWindow.java
new file mode 100644
index 00000000000..8d1f971a514
--- /dev/null
+++ b/src/main/java/seedu/address/ui/ViewPersonWindow.java
@@ -0,0 +1,82 @@
+package seedu.address.ui;
+
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.FlowPane;
+import javafx.stage.Stage;
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.model.person.Person;
+
+/**
+ * Controller for a view person page
+ */
+public class ViewPersonWindow extends UiPart {
+
+
+ public static final Logger LOGGER = LogsCenter.getLogger(ViewPersonWindow.class);
+ public static final String FXML = "ViewPersonWindow.fxml";
+
+ public final ObservableList person;
+
+ // Fields for the client
+ @FXML
+ private Label name;
+ @FXML
+ private Label phone;
+ @FXML
+ private Label address;
+ @FXML
+ private Label email;
+ @FXML
+ private Label description;
+ @FXML
+ private FlowPane clientTypes;
+
+ /**
+ * Creates a new ViewPersonWindow.
+ *
+ * @param person ObservableList of persons to view
+ */
+ public ViewPersonWindow(ObservableList person) {
+ super(FXML, new Stage());
+ this.person = person;
+
+ // Initialising values for the client
+ // Using streams to get the first person and set values
+ person.stream()
+ .findFirst()
+ .ifPresent(p -> {
+ name.setText(p.getName().fullName);
+ phone.setText(p.getPhone().value);
+ address.setText(p.getAddress().value);
+ email.setText(p.getEmail().value);
+ p.getClientTypes().forEach(clientType ->
+ clientTypes.getChildren().add(new Label(clientType.clientTypeName)));
+ description.setText(p.getDescription().description);
+ });
+ }
+
+ /**
+ * Shows the ViewPersonWindow.
+ */
+ public void show() {
+ LOGGER.fine("Viewing client details.");
+ getRoot().show();
+ getRoot().centerOnScreen();
+ }
+
+ public boolean isViewShowing() {
+ return getRoot().isShowing();
+ }
+
+ public void hide() {
+ getRoot().hide();
+ }
+
+ public void focus() {
+ getRoot().requestFocus();
+ }
+}
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
index 36e6b001cd8..2ae86f6894c 100644
--- a/src/main/resources/view/DarkTheme.css
+++ b/src/main/resources/view/DarkTheme.css
@@ -26,7 +26,7 @@
.text-field {
-fx-font-size: 12pt;
- -fx-font-family: "Segoe UI Semibold";
+ -fx-font-family: "Arial Rounded MT Bold";
}
.tab-pane {
@@ -94,40 +94,48 @@
}
.list-cell {
- -fx-label-padding: 0 0 0 0;
+ -fx-label-padding: 5 0 5 0;
-fx-graphic-text-gap : 0;
- -fx-padding: 0 0 0 0;
+ -fx-padding: 2 0 2 0;
+ -fx-background-insets: 10 0 10 0;
+ -fx-background-radius: 15;
+ -fx-border-radius: 15;
}
.list-cell:filled:even {
- -fx-background-color: #3c3e3f;
+ -fx-background-color: #ffffff;
}
.list-cell:filled:odd {
- -fx-background-color: #515658;
+ -fx-background-color: #ffffff;
}
.list-cell:filled:selected {
- -fx-background-color: #424d5f;
+ -fx-background-color: #b0b0c0;
}
.list-cell:filled:selected #cardPane {
- -fx-border-color: #3e7b91;
+ /*-fx-border-color: #151414;*/
-fx-border-width: 1;
}
.list-cell .label {
- -fx-text-fill: white;
+ -fx-text-fill: black;
}
+/* The following styles are used in the PersonCard */
+/* For the name attribute */
.cell_big_label {
- -fx-font-family: "Segoe UI Semibold";
- -fx-font-size: 16px;
+ /*-fx-font-family: "Segoe UI Semibold";*/
+ -fx-font-family: "Arial Rounded MT Bold";
+ -fx-font-size: 20px;
-fx-text-fill: #010504;
+ -fx-font-weight: bold;
}
+/* For the other attributes */
.cell_small_label {
- -fx-font-family: "Segoe UI";
+ -fx-font-family: "Arial Rounded MT Bold";
-fx-font-size: 13px;
-fx-text-fill: #010504;
}
@@ -148,7 +156,7 @@
.result-display {
-fx-background-color: transparent;
- -fx-font-family: "Segoe UI Light";
+ -fx-font-family: "Arial Rounded MT Bold";
-fx-font-size: 13pt;
-fx-text-fill: white;
}
@@ -310,6 +318,8 @@
#cardPane {
-fx-background-color: transparent;
-fx-border-width: 0;
+ -fx-background-radius: 20;
+ -fx-border-radius: 20;
}
#commandTypeLabel {
@@ -323,7 +333,7 @@
-fx-border-color: #383838 #383838 #ffffff #383838;
-fx-border-insets: 0;
-fx-border-width: 1;
- -fx-font-family: "Segoe UI Light";
+ -fx-font-family: "Arial Rounded MT Bold";
-fx-font-size: 13pt;
-fx-text-fill: white;
}
@@ -337,16 +347,31 @@
-fx-background-radius: 0;
}
-#tags {
+#clientTypes {
-fx-hgap: 7;
-fx-vgap: 3;
}
-#tags .label {
- -fx-text-fill: white;
- -fx-background-color: #3e7b91;
+#clientTypes .label {
+ -fx-text-fill: #ffffff;
+ -fx-background-color: #9156bb;
-fx-padding: 1 3 1 3;
- -fx-border-radius: 2;
+ -fx-border-radius: 10;
-fx-background-radius: 2;
-fx-font-size: 11;
+ -fx-font-family: "Arial Rounded MT Bold";
}
+
+.reminder-card {
+ -fx-background-color: transparent;
+ -fx-border-width: 0 0 1 0;
+ -fx-border-color: derive(#1d1d1d, 20%);
+ -fx-padding: 6 4 6 4;
+}
+
+.cell_small_label_bold {
+ -fx-font-weight: bold;
+ -fx-text-fill: red;
+}
+
+
diff --git a/src/main/resources/view/HelpWindow.css b/src/main/resources/view/HelpWindow.css
index 17e8a8722cd..330ce479be5 100644
--- a/src/main/resources/view/HelpWindow.css
+++ b/src/main/resources/view/HelpWindow.css
@@ -1,13 +1,17 @@
-#copyButton, #helpMessage {
- -fx-text-fill: white;
+#helpMessage{
+ -fx-text-fill: black;
}
#copyButton {
- -fx-background-color: dimgray;
+ -fx-text-fill: white;
+ -fx-font-family: "Arial Rounded MT Bold";
+ -fx-font-weight: bold;
+ -fx-background-color: #a232ea;
}
+
#copyButton:hover {
- -fx-background-color: gray;
+ -fx-background-color: #570987;
}
#copyButton:armed {
@@ -15,5 +19,58 @@
}
#helpMessageContainer {
- -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-background-color: #ffffff;
+}
+
+#moreInfoContainer {
+ -fx-background-color: #ffffff;
+ -fx-font-family: "Arial Rounded MT Bold";
+ -fx-min-height: 80;
+}
+
+.helpMessageWrapper{
+ -fx-background-color: #dedede;
+ -fx-min-height: 5;
+ -fx-min-width: 100;
+ -fx-content-display: CENTER;
+ -fx-alignment: CENTER;
+ -fx-background-radius: 10;
+ -fx-border-radius: 10;
+ -fx-padding: 15;
+
+}
+
+.commandContainer {
+ -fx-background-color: transparent;
+ -fx-border-width: 0;
+ -fx-background-radius: 20;
+ -fx-border-radius: 20;
+}
+
+.headerLabel {
+ -fx-font-family: "Arial Rounded MT Bold";
+ -fx-font-size: 20px;
+ -fx-text-fill: #000000;
+ -fx-font-weight: bold;
+}
+
+.commandLabel {
+ -fx-font-family: "Andale Mono";
+ -fx-font-size: 15px;
+ -fx-text-fill: black;
+}
+
+.orLabel {
+ -fx-font-family: "Arial Rounded MT Bold";
+ -fx-font-size: 15px;
+ -fx-text-fill: black;
+ -fx-font-weight: bold;
+}
+
+.commandWrapper {
+ -fx-background-color: #f5f5f5;
+ -fx-padding: 10;
+ -fx-background-radius: 5;
+ -fx-pref-width: 300;
+ -fx-pref-height: 100;
}
diff --git a/src/main/resources/view/HelpWindow.fxml b/src/main/resources/view/HelpWindow.fxml
index e01f330de33..6a3a24aaf2e 100644
--- a/src/main/resources/view/HelpWindow.fxml
+++ b/src/main/resources/view/HelpWindow.fxml
@@ -7,9 +7,12 @@
+
+
-
+
+
@@ -19,26 +22,225 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
index 7778f666a0a..81aee2f08db 100644
--- a/src/main/resources/view/MainWindow.fxml
+++ b/src/main/resources/view/MainWindow.fxml
@@ -6,24 +6,29 @@
-
+
+
+ title="ClientHub" minWidth="1000" minHeight="800" onCloseRequest="#handleExit">
+
-
+
+
+
+
@@ -33,12 +38,14 @@
+
+
@@ -46,12 +53,24 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml
index 84e09833a87..f2e07a69f05 100644
--- a/src/main/resources/view/PersonListCard.fxml
+++ b/src/main/resources/view/PersonListCard.fxml
@@ -14,11 +14,11 @@
-
+
-
+
@@ -27,7 +27,7 @@
-
+
diff --git a/src/main/resources/view/ReminderCard.fxml b/src/main/resources/view/ReminderCard.fxml
new file mode 100644
index 00000000000..d3b58ba1742
--- /dev/null
+++ b/src/main/resources/view/ReminderCard.fxml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/ReminderListPanel.fxml b/src/main/resources/view/ReminderListPanel.fxml
new file mode 100644
index 00000000000..ba574ca8eb8
--- /dev/null
+++ b/src/main/resources/view/ReminderListPanel.fxml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/ViewPersonWindow.css b/src/main/resources/view/ViewPersonWindow.css
new file mode 100644
index 00000000000..19b9bbd88e3
--- /dev/null
+++ b/src/main/resources/view/ViewPersonWindow.css
@@ -0,0 +1,9 @@
+#clientTypes .label {
+ -fx-text-fill: #ffffff;
+ -fx-background-color: #9156bb;
+ -fx-padding: 1 3 1 3;
+ -fx-border-radius: 10;
+ -fx-background-radius: 2;
+ -fx-font-size: 11;
+ -fx-font-family: "Arial Rounded MT Bold";
+}
diff --git a/src/main/resources/view/ViewPersonWindow.fxml b/src/main/resources/view/ViewPersonWindow.fxml
new file mode 100644
index 00000000000..27e419b4497
--- /dev/null
+++ b/src/main/resources/view/ViewPersonWindow.fxml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
deleted file mode 100644
index ccd21f7d1a9..00000000000
--- a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "persons": [ {
- "name": "Person with invalid name field: Ha!ns Mu@ster",
- "phone": "9482424",
- "email": "hans@example.com",
- "address": "4th street"
- } ]
-}
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json b/src/test/data/JsonClientHubStorageTest/invalidAndValidPersonClientHub.json
similarity index 64%
rename from src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
rename to src/test/data/JsonClientHubStorageTest/invalidAndValidPersonClientHub.json
index 6a4d2b7181c..14492d41f13 100644
--- a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
+++ b/src/test/data/JsonClientHubStorageTest/invalidAndValidPersonClientHub.json
@@ -3,11 +3,13 @@
"name": "Valid Person",
"phone": "9482424",
"email": "hans@example.com",
- "address": "4th street"
+ "address": "4th street",
+ "description": "Valid"
}, {
"name": "Person With Invalid Phone Field",
"phone": "948asdf2424",
"email": "hans@example.com",
- "address": "4th street"
+ "address": "4th street",
+ "description": "Invalid phone field"
} ]
}
diff --git a/src/test/data/JsonClientHubStorageTest/invalidPersonClientHub.json b/src/test/data/JsonClientHubStorageTest/invalidPersonClientHub.json
new file mode 100644
index 00000000000..c5a9bebd6c5
--- /dev/null
+++ b/src/test/data/JsonClientHubStorageTest/invalidPersonClientHub.json
@@ -0,0 +1,11 @@
+{
+ "persons": [ {
+ "name": "Person with invalid name field: Ha!ns Mu@ster",
+ "phone": "9482424",
+ "email": "hans@example.com",
+ "address": "4th street",
+ "clientTypes": [ "client" ],
+ "description": "Embracing change can lead to new opportunities and growth, allowing us to discover our potential and navigate life's challenges with renewed strength.",
+ "reminders": [ ]
+ } ]
+}
diff --git a/src/test/data/JsonAddressBookStorageTest/notJsonFormatAddressBook.json b/src/test/data/JsonClientHubStorageTest/notJsonFormatClientHub.json
similarity index 100%
rename from src/test/data/JsonAddressBookStorageTest/notJsonFormatAddressBook.json
rename to src/test/data/JsonClientHubStorageTest/notJsonFormatClientHub.json
diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
deleted file mode 100644
index ad3f135ae42..00000000000
--- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "persons": [ {
- "name": "Hans Muster",
- "phone": "9482424",
- "email": "invalid@email!3e",
- "address": "4th street"
- } ]
-}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
deleted file mode 100644
index 72262099d35..00000000000
--- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "_comment": "AddressBook save file which contains the same Person values as in TypicalPersons#getTypicalAddressBook()",
- "persons" : [ {
- "name" : "Alice Pauline",
- "phone" : "94351253",
- "email" : "alice@example.com",
- "address" : "123, Jurong West Ave 6, #08-111",
- "tags" : [ "friends" ]
- }, {
- "name" : "Benson Meier",
- "phone" : "98765432",
- "email" : "johnd@example.com",
- "address" : "311, Clementi Ave 2, #02-25",
- "tags" : [ "owesMoney", "friends" ]
- }, {
- "name" : "Carl Kurz",
- "phone" : "95352563",
- "email" : "heinz@example.com",
- "address" : "wall street",
- "tags" : [ ]
- }, {
- "name" : "Daniel Meier",
- "phone" : "87652533",
- "email" : "cornelia@example.com",
- "address" : "10th street",
- "tags" : [ "friends" ]
- }, {
- "name" : "Elle Meyer",
- "phone" : "9482224",
- "email" : "werner@example.com",
- "address" : "michegan ave",
- "tags" : [ ]
- }, {
- "name" : "Fiona Kunz",
- "phone" : "9482427",
- "email" : "lydia@example.com",
- "address" : "little tokyo",
- "tags" : [ ]
- }, {
- "name" : "George Best",
- "phone" : "9482442",
- "email" : "anna@example.com",
- "address" : "4th street",
- "tags" : [ ]
- } ]
-}
diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializableClientHubTest/duplicatePersonClientHub.json
similarity index 56%
rename from src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
rename to src/test/data/JsonSerializableClientHubTest/duplicatePersonClientHub.json
index a7427fe7aa2..6bff36503cf 100644
--- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
+++ b/src/test/data/JsonSerializableClientHubTest/duplicatePersonClientHub.json
@@ -4,11 +4,15 @@
"phone": "94351253",
"email": "alice@example.com",
"address": "123, Jurong West Ave 6, #08-111",
- "tags": [ "friends" ]
+ "clientTypes": [ "A" ],
+ "description": "Alice is a very good client.",
+ "reminders": [ ]
}, {
"name": "Alice Pauline",
"phone": "94351253",
"email": "pauline@example.com",
- "address": "4th street"
+ "address": "4th street",
+ "description": "Alice is a very good client.",
+ "reminders": [ ]
} ]
}
diff --git a/src/test/data/JsonSerializableClientHubTest/invalidPersonClientHub.json b/src/test/data/JsonSerializableClientHubTest/invalidPersonClientHub.json
new file mode 100644
index 00000000000..6916730b41f
--- /dev/null
+++ b/src/test/data/JsonSerializableClientHubTest/invalidPersonClientHub.json
@@ -0,0 +1,10 @@
+{
+ "persons": [ {
+ "name": "Hans Muster",
+ "phone": "9482424",
+ "email": "invalid@email!3e",
+ "address": "4th street",
+ "clientTypes:": [ "client" ],
+ "description": "Embracing change can lead to new opportunities and growth, allowing us to discover our potential and navigate life's challenges with renewed strength."
+ } ]
+}
diff --git a/src/test/data/JsonSerializableClientHubTest/typicalPersonsClientHub.json b/src/test/data/JsonSerializableClientHubTest/typicalPersonsClientHub.json
new file mode 100644
index 00000000000..4950949e162
--- /dev/null
+++ b/src/test/data/JsonSerializableClientHubTest/typicalPersonsClientHub.json
@@ -0,0 +1,84 @@
+{
+ "_comment": "ClientHub save file which contains the same Person values as in TypicalPersons#getTypicalClientHub()",
+ "persons" : [ {
+ "name" : "Alice Pauline",
+ "phone" : "94351253",
+ "email" : "alice@example.com",
+ "address" : "123, Jurong West Ave 6, #08-111",
+ "clientTypes" : [ "Investment" ],
+ "description" : "A type",
+ "reminders" : [{
+ "personName" : "Alice Pauline",
+ "dateTime" : "2024-10-10 11:11",
+ "reminderDescription" : "Reminder 1"
+ }]
+ }, {
+ "name" : "Benson Meier",
+ "phone" : "98765432",
+ "email" : "johnd@example.com",
+ "address" : "311, Clementi Ave 2, #02-25",
+ "clientTypes" : [ "Investment", "Savings" ],
+ "description" : "Likes to eat a lot",
+ "reminders" : [{
+ "personName" : "Benson Meier",
+ "dateTime" : "2024-11-10 06:11",
+ "reminderDescription" : "Reminder 2"
+ }]
+ }, {
+ "name" : "Carl Kurz",
+ "phone" : "95352563",
+ "email" : "heinz@example.com",
+ "address" : "wall street",
+ "clientTypes" : [ "Investment", "Healthcare" ],
+ "description" : "Likes to eat a lot",
+ "reminders" : [{
+ "personName" : "Carl Kurz",
+ "dateTime" : "2024-12-10 07:11",
+ "reminderDescription" : "Reminder 3"
+ }]
+ }, {
+ "name" : "Daniel Meier",
+ "phone" : "87652533",
+ "email" : "cornelia@example.com",
+ "address" : "10th street",
+ "clientTypes" : [ "B" ],
+ "description" : "Likes to eat a lot",
+ "reminders" : []
+ }, {
+ "name" : "Elle Meyer",
+ "phone" : "94822241",
+ "email" : "werner@example.com",
+ "address" : "michegan ave",
+ "clientTypes" : [ "A" ],
+ "description" : "Likes to eat a lot",
+ "reminders" : []
+ }, {
+ "name" : "Fiona Kunz",
+ "phone" : "94824271",
+ "email" : "lydia@example.com",
+ "address" : "little tokyo",
+ "clientTypes" : [ "A" ],
+ "description" : "Likes to eat a lot",
+ "reminders" : []
+ }, {
+ "name" : "George Best",
+ "phone" : "94824421",
+ "email" : "anna@example.com",
+ "address" : "4th street",
+ "clientTypes" : [ "A" ],
+ "description" : "Likes to eat a lot",
+ "reminders" : []
+ }, {
+ "name" : "Alice Potter",
+ "phone" : "99924422",
+ "email" : "APotter@example.com",
+ "address" : "china",
+ "clientTypes" : [ "A" ],
+ "description" : "Likes to eat a lot",
+ "reminders" : [{
+ "personName" : "Alice Potter",
+ "dateTime" : "2024-12-10 07:11",
+ "reminderDescription" : "Reminder 5"
+ }]
+ }]
+}
diff --git a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
index 1037548a9cd..0e7ae8cf347 100644
--- a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
+++ b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
@@ -9,5 +9,5 @@
"z" : 99
}
},
- "addressBookFilePath" : "addressbook.json"
+ "clientHubFilePath" : "clienthub.json"
}
diff --git a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
index b819bed900a..ddd0f247e66 100644
--- a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
+++ b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
@@ -7,5 +7,5 @@
"y" : 100
}
},
- "addressBookFilePath" : "addressbook.json"
+ "clientHubFilePath" : "clienthub.json"
}
diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java
index baf8ce336a2..0853c317de9 100644
--- a/src/test/java/seedu/address/logic/LogicManagerTest.java
+++ b/src/test/java/seedu/address/logic/LogicManagerTest.java
@@ -1,9 +1,12 @@
package seedu.address.logic;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static seedu.address.logic.Messages.MESSAGE_PERSON_NOT_FOUND;
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.CLIENT_TYPE_DESC_A;
+import static seedu.address.logic.commands.CommandTestUtil.DESCRIPTION_DESC_A;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
@@ -18,6 +21,8 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import javafx.collections.ObservableList;
+import seedu.address.commons.core.GuiSettings;
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.commands.CommandResult;
import seedu.address.logic.commands.ListCommand;
@@ -25,10 +30,11 @@
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyClientHub;
import seedu.address.model.UserPrefs;
import seedu.address.model.person.Person;
-import seedu.address.storage.JsonAddressBookStorage;
+import seedu.address.model.reminder.Reminder;
+import seedu.address.storage.JsonClientHubStorage;
import seedu.address.storage.JsonUserPrefsStorage;
import seedu.address.storage.StorageManager;
import seedu.address.testutil.PersonBuilder;
@@ -45,10 +51,10 @@ public class LogicManagerTest {
@BeforeEach
public void setUp() {
- JsonAddressBookStorage addressBookStorage =
- new JsonAddressBookStorage(temporaryFolder.resolve("addressBook.json"));
+ JsonClientHubStorage clientHubStorage =
+ new JsonClientHubStorage(temporaryFolder.resolve("clientHub.json"));
JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("userPrefs.json"));
- StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage);
+ StorageManager storage = new StorageManager(clientHubStorage, userPrefsStorage);
logic = new LogicManager(model, storage);
}
@@ -60,8 +66,9 @@ public void execute_invalidCommandFormat_throwsParseException() {
@Test
public void execute_commandExecutionError_throwsCommandException() {
- String deleteCommand = "delete 9";
- assertCommandException(deleteCommand, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ String deleteCommand = "delete invalidName";
+ assertCommandException(deleteCommand, MESSAGE_PERSON_NOT_FOUND);
+
}
@Test
@@ -83,8 +90,8 @@ public void execute_storageThrowsAdException_throwsCommandException() {
}
@Test
- public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException() {
- assertThrows(UnsupportedOperationException.class, () -> logic.getFilteredPersonList().remove(0));
+ public void getPersonList_modifyList_throwsUnsupportedOperationException() {
+ assertThrows(UnsupportedOperationException.class, () -> logic.getPersonList().remove(0));
}
/**
@@ -123,7 +130,7 @@ private void assertCommandException(String inputCommand, String expectedMessage)
*/
private void assertCommandFailure(String inputCommand, Class extends Throwable> expectedException,
String expectedMessage) {
- Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ Model expectedModel = new ModelManager(model.getClientHub(), new UserPrefs());
assertCommandFailure(inputCommand, expectedException, expectedMessage, expectedModel);
}
@@ -149,10 +156,10 @@ private void assertCommandFailure(String inputCommand, Class extends Throwable
private void assertCommandFailureForExceptionFromStorage(IOException e, String expectedMessage) {
Path prefPath = temporaryFolder.resolve("ExceptionUserPrefs.json");
- // Inject LogicManager with an AddressBookStorage that throws the IOException e when saving
- JsonAddressBookStorage addressBookStorage = new JsonAddressBookStorage(prefPath) {
+ // Inject LogicManager with a ClientHubStorage that throws the IOException e when saving
+ JsonClientHubStorage clientHubStorage = new JsonClientHubStorage(prefPath) {
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath)
+ public void saveClientHub(ReadOnlyClientHub clientHub, Path filePath)
throws IOException {
throw e;
}
@@ -160,16 +167,67 @@ public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath)
JsonUserPrefsStorage userPrefsStorage =
new JsonUserPrefsStorage(temporaryFolder.resolve("ExceptionUserPrefs.json"));
- StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage);
+ StorageManager storage = new StorageManager(clientHubStorage, userPrefsStorage);
logic = new LogicManager(model, storage);
- // Triggers the saveAddressBook method by executing an add command
+ // Triggers the saveClientHub 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 + ADDRESS_DESC_AMY + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_A;
+ Person expectedPerson = new PersonBuilder(AMY).build();
ModelManager expectedModel = new ModelManager();
expectedModel.addPerson(expectedPerson);
assertCommandFailure(addCommand, CommandException.class, expectedMessage, expectedModel);
}
+
+ @Test
+ public void getClientHub_returnsNonNullClientHub() {
+ ReadOnlyClientHub clientHub = logic.getClientHub();
+ assertNotNull(clientHub, "ClientHub should not be null.");
+ }
+
+ @Test
+ public void getClientHub_returnsExpectedData() {
+ // Assuming model initially has an empty ClientHub
+ ReadOnlyClientHub clientHub = logic.getClientHub();
+ assertEquals(0, clientHub.getPersonList().size(), "ClientHub should initially contain no persons.");
+ }
+
+ @Test
+ public void getPersonList_returnsObservableListOfPersons() {
+ ObservableList personList = logic.getPersonList();
+ assertNotNull(personList, "Person list should not be null.");
+ assertEquals(0, personList.size(), "Initial person list should be empty.");
+ }
+
+ @Test
+ public void getReminderList_returnsObservableListOfReminders() {
+ ObservableList reminderList = logic.getReminderList();
+ assertNotNull(reminderList, "Reminder list should not be null.");
+ assertEquals(0, reminderList.size(), "Initial reminder list should be empty.");
+ }
+
+ @Test
+ public void getClientHubFilePath_returnsCorrectPath() {
+ Path clientHubFilePath = logic.getClientHubFilePath();
+ assertNotNull(clientHubFilePath, "ClientHub file path should not be null.");
+ }
+
+ @Test
+ public void getGuiSettings_returnsDefaultGuiSettings() {
+ GuiSettings guiSettings = logic.getGuiSettings();
+ assertNotNull(guiSettings, "GuiSettings should not be null.");
+ assertEquals(new GuiSettings(), guiSettings, "Initial GuiSettings should match default settings.");
+ }
+
+ @Test
+ public void setGuiSettings_updatesGuiSettings() {
+ GuiSettings newSettings = new GuiSettings(800, 600, 100, 100); // Custom GuiSettings for test
+ logic.setGuiSettings(newSettings);
+ assertEquals(newSettings, logic.getGuiSettings(), "GuiSettings should update to new values.");
+ }
+ @Test
+ public void getReminderList_modifyList_throwsUnsupportedOperationException() {
+ assertThrows(UnsupportedOperationException.class, () -> logic.getReminderList().remove(0));
+ }
}
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
index 162a0c86031..c3e88c7d5f0 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
@@ -2,7 +2,7 @@
import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -23,14 +23,14 @@ public class AddCommandIntegrationTest {
@BeforeEach
public void setUp() {
- model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ model = new ModelManager(getTypicalClientHub(), new UserPrefs());
}
@Test
public void execute_newPerson_success() {
Person validPerson = new PersonBuilder().build();
- Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ Model expectedModel = new ModelManager(model.getClientHub(), new UserPrefs());
expectedModel.addPerson(validPerson);
assertCommandSuccess(new AddCommand(validPerson), model,
@@ -40,7 +40,7 @@ public void execute_newPerson_success() {
@Test
public void execute_duplicatePerson_throwsCommandException() {
- Person personInList = model.getAddressBook().getPersonList().get(0);
+ Person personInList = model.getClientHub().getPersonList().get(0);
assertCommandFailure(new AddCommand(personInList), model,
AddCommand.MESSAGE_DUPLICATE_PERSON);
}
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
index 90e8253f48e..97bfd1009f8 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
@@ -10,6 +10,7 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
import java.util.function.Predicate;
import org.junit.jupiter.api.Test;
@@ -18,11 +19,12 @@
import seedu.address.commons.core.GuiSettings;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.AddressBook;
+import seedu.address.model.ClientHub;
import seedu.address.model.Model;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyClientHub;
import seedu.address.model.ReadOnlyUserPrefs;
import seedu.address.model.person.Person;
+import seedu.address.model.reminder.Reminder;
import seedu.address.testutil.PersonBuilder;
public class AddCommandTest {
@@ -109,12 +111,12 @@ public void setGuiSettings(GuiSettings guiSettings) {
}
@Override
- public Path getAddressBookFilePath() {
+ public Path getClientHubFilePath() {
throw new AssertionError("This method should not be called.");
}
@Override
- public void setAddressBookFilePath(Path addressBookFilePath) {
+ public void setClientHubFilePath(Path clientHubFilePath) {
throw new AssertionError("This method should not be called.");
}
@@ -124,12 +126,27 @@ public void addPerson(Person person) {
}
@Override
- public void setAddressBook(ReadOnlyAddressBook newData) {
+ public void addReminder(Reminder reminder) {
+
+ }
+
+ @Override
+ public int getDisplayPersonsListSize() {
+ return this.getDisplayPersons().size();
+ }
+
+ @Override
+ public int getDisplayRemindersListSize() {
+ return 0;
+ }
+
+ @Override
+ public void setClientHub(ReadOnlyClientHub newData) {
throw new AssertionError("This method should not be called.");
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
+ public ReadOnlyClientHub getClientHub() {
throw new AssertionError("This method should not be called.");
}
@@ -138,18 +155,48 @@ public boolean hasPerson(Person person) {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public boolean hasReminder(Reminder reminder) {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public void deletePerson(Person target) {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public void deleteReminder(Reminder target) {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public void setPerson(Person target, Person editedPerson) {
throw new AssertionError("This method should not be called.");
}
@Override
- public ObservableList getFilteredPersonList() {
+ public void setReminder(Reminder target, Reminder editedReminder) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ObservableList getDisplayPersons() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public ObservableList getDisplayReminders() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void updateUnfilteredList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void updateUnfilteredReminderList() {
throw new AssertionError("This method should not be called.");
}
@@ -157,6 +204,16 @@ public ObservableList getFilteredPersonList() {
public void updateFilteredPersonList(Predicate predicate) {
throw new AssertionError("This method should not be called.");
}
+
+ @Override
+ public void updateFilteredReminderList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void updateSortedPersonList(Comparator comparator) {
+ throw new AssertionError("This method should not be called.");
+ }
}
/**
@@ -196,8 +253,8 @@ public void addPerson(Person person) {
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
- return new AddressBook();
+ public ReadOnlyClientHub getClientHub() {
+ return new ClientHub();
}
}
diff --git a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java b/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
index 80d9110c03a..c47c4e63bb5 100644
--- a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
@@ -1,11 +1,11 @@
package seedu.address.logic.commands;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
import org.junit.jupiter.api.Test;
-import seedu.address.model.AddressBook;
+import seedu.address.model.ClientHub;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
@@ -13,7 +13,7 @@
public class ClearCommandTest {
@Test
- public void execute_emptyAddressBook_success() {
+ public void execute_emptyClientHub_success() {
Model model = new ModelManager();
Model expectedModel = new ModelManager();
@@ -21,10 +21,10 @@ public void execute_emptyAddressBook_success() {
}
@Test
- public void execute_nonEmptyAddressBook_success() {
- Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
- Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
- expectedModel.setAddressBook(new AddressBook());
+ public void execute_nonEmptyClientHub_success() {
+ Model model = new ModelManager(getTypicalClientHub(), new UserPrefs());
+ Model expectedModel = new ModelManager(getTypicalClientHub(), new UserPrefs());
+ expectedModel.setClientHub(new ClientHub());
assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel);
}
diff --git a/src/test/java/seedu/address/logic/commands/CommandResultTest.java b/src/test/java/seedu/address/logic/commands/CommandResultTest.java
index 7b8c7cd4546..594f70d6da8 100644
--- a/src/test/java/seedu/address/logic/commands/CommandResultTest.java
+++ b/src/test/java/seedu/address/logic/commands/CommandResultTest.java
@@ -14,7 +14,8 @@ 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 +30,16 @@ 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 showView value -> returns false
+ assertFalse(commandResult.equals(new CommandResult("feedback",
+ false, true, false)));
// different exit value -> returns false
- assertFalse(commandResult.equals(new CommandResult("feedback", false, true)));
+ assertFalse(commandResult.equals(new CommandResult("feedback",
+ false, false, true)));
}
@Test
@@ -46,17 +53,25 @@ 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 showView value -> returns different hashcode
+ assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false,
+ true, false).hashCode());
// different exit value -> returns different hashcode
- assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false, true).hashCode());
+ assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false,
+ false, true).hashCode());
}
@Test
public void toStringMethod() {
CommandResult commandResult = new CommandResult("feedback");
String expected = CommandResult.class.getCanonicalName() + "{feedbackToUser="
- + commandResult.getFeedbackToUser() + ", showHelp=" + commandResult.isShowHelp()
+ + commandResult.getFeedbackToUser()
+ + ", showHelp=" + commandResult.isShowHelp()
+ + ", showView=" + commandResult.isShowView()
+ ", exit=" + commandResult.isExit() + "}";
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..423def0a0fb 100644
--- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
+++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
@@ -3,10 +3,11 @@
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_CLIENT_TYPE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import static seedu.address.testutil.Assert.assertThrows;
import java.util.ArrayList;
@@ -15,7 +16,7 @@
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.AddressBook;
+import seedu.address.model.ClientHub;
import seedu.address.model.Model;
import seedu.address.model.person.NameContainsKeywordsPredicate;
import seedu.address.model.person.Person;
@@ -34,8 +35,10 @@ public class CommandTestUtil {
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_CLIENT_TYPE_A = "A";
+ public static final String VALID_CLIENT_TYPE_B = "B";
+ public static final String VALID_DESCRIPTION_A = "A thing";
+ public static final String VALID_DESCRIPTION_B = "B thing";
public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY;
public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB;
@@ -45,14 +48,25 @@ public class CommandTestUtil {
public static final String EMAIL_DESC_BOB = " " + PREFIX_EMAIL + VALID_EMAIL_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 CLIENT_TYPE_DESC_A = " " + PREFIX_CLIENT_TYPE + VALID_CLIENT_TYPE_A;
+ public static final String CLIENT_TYPE_DESC_B = " " + PREFIX_CLIENT_TYPE + VALID_CLIENT_TYPE_B;
+ public static final String DESCRIPTION_DESC_A = " " + PREFIX_DESCRIPTION + VALID_DESCRIPTION_A;
+ public static final String DESCRIPTION_DESC_B = " " + PREFIX_DESCRIPTION + VALID_DESCRIPTION_B;
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_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_CLIENT_TYPE_DESC = " "
+ + PREFIX_CLIENT_TYPE + "hubby*"; // '*' not allowed in client types
+ public static final String INVALID_DESCRIPTION_DESC = " "
+ + PREFIX_DESCRIPTION + "apple banana orange mango grape lemon peach pear strawberry blueberry "
+ + "raspberry watermelon pineapple kiwi cherry lime grapefruit apricot plum coconut "
+ + "fig date nectarine cantaloupe guava papaya pomegranate cranberry tangerine blackberry currant "
+ + "dragonfruit lychee persimmon quince starfruit avocado passionfruit gooseberry mulberry "
+ + "elderberry boysenberry kumquat jujube "
+ + "yuzu ackee rambutan loquat carambola jabuticaba sapodilla medlar feijoa pawpaw salak "
+ + "tamarillo lucuma BLAH BLAH BLAH BLAH BLAH BLAH BLAH";
public static final String PREAMBLE_WHITESPACE = "\t \r \n";
public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble";
@@ -63,10 +77,11 @@ 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();
+ .withClientTypes(VALID_CLIENT_TYPE_A).withDescription(VALID_DESCRIPTION_A).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();
+ .withClientTypes(VALID_CLIENT_TYPE_B, VALID_CLIENT_TYPE_A)
+ .withDescription(VALID_DESCRIPTION_B).build();
}
/**
@@ -75,7 +90,7 @@ public class CommandTestUtil {
* - the {@code actualModel} matches {@code expectedModel}
*/
public static void assertCommandSuccess(Command command, Model actualModel, CommandResult expectedCommandResult,
- Model expectedModel) {
+ Model expectedModel) {
try {
CommandResult result = command.execute(actualModel);
assertEquals(expectedCommandResult, result);
@@ -90,7 +105,7 @@ public static void assertCommandSuccess(Command command, Model actualModel, Comm
* that takes a string {@code expectedMessage}.
*/
public static void assertCommandSuccess(Command command, Model actualModel, String expectedMessage,
- Model expectedModel) {
+ Model expectedModel) {
CommandResult expectedCommandResult = new CommandResult(expectedMessage);
assertCommandSuccess(command, actualModel, expectedCommandResult, expectedModel);
}
@@ -104,25 +119,41 @@ public static void assertCommandSuccess(Command command, Model actualModel, Stri
public static void assertCommandFailure(Command command, Model actualModel, String expectedMessage) {
// we are unable to defensively copy the model for comparison later, so we can
// only do so by copying its components.
- AddressBook expectedAddressBook = new AddressBook(actualModel.getAddressBook());
- List expectedFilteredList = new ArrayList<>(actualModel.getFilteredPersonList());
+ ClientHub expectedClientHub = new ClientHub(actualModel.getClientHub());
+ List expectedFilteredList = new ArrayList<>(actualModel.getDisplayPersons());
assertThrows(CommandException.class, expectedMessage, () -> command.execute(actualModel));
- assertEquals(expectedAddressBook, actualModel.getAddressBook());
- assertEquals(expectedFilteredList, actualModel.getFilteredPersonList());
+ assertEquals(expectedClientHub, actualModel.getClientHub());
+ assertEquals(expectedFilteredList, actualModel.getDisplayPersons());
}
+
+
/**
* Updates {@code model}'s filtered list to show only the person at the given {@code targetIndex} in the
* {@code model}'s address book.
*/
public static void showPersonAtIndex(Model model, Index targetIndex) {
- assertTrue(targetIndex.getZeroBased() < model.getFilteredPersonList().size());
+ assertTrue(targetIndex.getZeroBased() < model.getDisplayPersons().size());
- Person person = model.getFilteredPersonList().get(targetIndex.getZeroBased());
+ Person person = model.getDisplayPersons().get(targetIndex.getZeroBased());
final String[] splitName = person.getName().fullName.split("\\s+");
- model.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(splitName[0])));
+ model.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(splitName)));
+
+ assertEquals(1, model.getDisplayPersons().size());
+ }
- assertEquals(1, model.getFilteredPersonList().size());
+ /**
+ * Asserts that the given {@code command} successfully deletes the person with the given {@code name} in the
+ * {@code actualModel}, and the filtered list in the {@code actualModel} is updated to show all persons.
+ */
+ public static void assertCommandFailureWithNewList(Command command, String userInput,
+ Model actualModel, String expectedMessage) {
+ List expectedFilteredList = new ArrayList<>(actualModel.getDisplayPersons())
+ .stream().filter(p -> p.getName().fullName
+ .toLowerCase().contains(userInput.toLowerCase())).toList();
+
+ assertThrows(CommandException.class, expectedMessage, () -> command.execute(actualModel));
+ assertEquals(expectedFilteredList, actualModel.getDisplayPersons());
}
}
diff --git a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
index b6f332eabca..362534bd1ff 100644
--- a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
@@ -4,91 +4,120 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailureWithNewList;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
+import static seedu.address.testutil.Assert.assertThrows;
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 static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_PERSON;
+import static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
+
+import java.util.Arrays;
+import java.util.List;
import org.junit.jupiter.api.Test;
-import seedu.address.commons.core.index.Index;
import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.ClientHub;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
+import seedu.address.model.person.NameContainsKeywordsDeletePredicate;
import seedu.address.model.person.Person;
+
/**
* Contains integration tests (interaction with the Model) and unit tests for
* {@code DeleteCommand}.
*/
public class DeleteCommandTest {
- private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model model = new ModelManager(getTypicalClientHub(), new UserPrefs());
@Test
- public void execute_validIndexUnfilteredList_success() {
- Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+ public void execute_validNameUnfilteredList_success() {
+ // Retrieve the person to delete based on the first index of the unfiltered list
+ Person personToDelete = model.getDisplayPersons().get(INDEX_THIRD_PERSON.getZeroBased() + 1);
+
+ // Create the predicate to match the person based on the name
+ NameContainsKeywordsDeletePredicate predicate = new NameContainsKeywordsDeletePredicate(
+ Arrays.asList(personToDelete.getName().fullName.split("\\s+")));
+ // Create the DeleteCommand using the predicate
+ DeleteCommand deleteCommand = new DeleteCommand(predicate);
+
+ // Expected success message after the person is deleted
String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
Messages.format(personToDelete));
- ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ // Create the expected model and perform the delete operation on it
+ ModelManager expectedModel = new ModelManager(model.getClientHub(), new UserPrefs());
expectedModel.deletePerson(personToDelete);
+ // Perform the command and verify that the expected model and actual model match
assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
}
@Test
- public void execute_invalidIndexUnfilteredList_throwsCommandException() {
- Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
- DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
+ public void execute_invalidNameUnfilteredList_throwsCommandException() {
+ NameContainsKeywordsDeletePredicate predicate = new NameContainsKeywordsDeletePredicate(
+ Arrays.asList("InvalidName".split("\\s+")));
+ DeleteCommand deleteCommand = new DeleteCommand(predicate);
- assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(deleteCommand, model, Messages.MESSAGE_PERSON_NOT_FOUND);
}
+
+
@Test
- public void execute_validIndexFilteredList_success() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ public void execute_validNameFilteredList_success() {
+ Person personToDelete = model.getDisplayPersons().get(INDEX_THIRD_PERSON.getZeroBased() + 1);
+ DeleteCommand deleteCommand = new DeleteCommand(new NameContainsKeywordsDeletePredicate(
+ Arrays.asList(personToDelete.getName().fullName.split("\\s+"))));
- Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
Messages.format(personToDelete));
- Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ Model expectedModel = new ModelManager(model.getClientHub(), new UserPrefs());
expectedModel.deletePerson(personToDelete);
- showNoPerson(expectedModel);
assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
}
@Test
- public void execute_invalidIndexFilteredList_throwsCommandException() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ public void duplicateNameFilteredList_throwsCommandException() {
+ Person personToDelete = model.getDisplayPersons().get(INDEX_FIRST_PERSON.getZeroBased());
+ String name = personToDelete.getName().fullName.split("\\s+")[0];
+ DeleteCommand deleteCommand = new DeleteCommand(new NameContainsKeywordsDeletePredicate(
+ Arrays.asList(name.split("\\s+"))));
- Index outOfBoundIndex = INDEX_SECOND_PERSON;
- // ensures that outOfBoundIndex is still in bounds of address book list
- assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
+ String expectedMessage = Messages.MESSAGE_VAGUE_DELETE;
- DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
+ ClientHub expectedClientHub = new ClientHub(model.getClientHub());
+ List expectedFilteredList = expectedClientHub.getPersonList().filtered(p -> p.getName().fullName
+ .toLowerCase().contains(name.toLowerCase()));
- assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertThrows(CommandException.class, expectedMessage, () -> deleteCommand.execute(model));
+ assertEquals(expectedClientHub, model.getClientHub());
+ assertEquals(expectedFilteredList, model.getDisplayPersons());
}
+
@Test
public void equals() {
- DeleteCommand deleteFirstCommand = new DeleteCommand(INDEX_FIRST_PERSON);
- DeleteCommand deleteSecondCommand = new DeleteCommand(INDEX_SECOND_PERSON);
+ DeleteCommand deleteFirstCommand = new DeleteCommand(new NameContainsKeywordsDeletePredicate(
+ Arrays.asList("first".split("\\s+"))));
+ DeleteCommand deleteSecondCommand = new DeleteCommand(new NameContainsKeywordsDeletePredicate(
+ Arrays.asList("second".split("\\s+"))));
// same object -> returns true
assertTrue(deleteFirstCommand.equals(deleteFirstCommand));
// same values -> returns true
- DeleteCommand deleteFirstCommandCopy = new DeleteCommand(INDEX_FIRST_PERSON);
+ DeleteCommand deleteFirstCommandCopy = new DeleteCommand(new NameContainsKeywordsDeletePredicate(
+ Arrays.asList("first".split("\\s+"))));
assertTrue(deleteFirstCommand.equals(deleteFirstCommandCopy));
// different types -> returns false
@@ -103,9 +132,10 @@ public void equals() {
@Test
public void toStringMethod() {
- Index targetIndex = Index.fromOneBased(1);
- DeleteCommand deleteCommand = new DeleteCommand(targetIndex);
- String expected = DeleteCommand.class.getCanonicalName() + "{targetIndex=" + targetIndex + "}";
+ NameContainsKeywordsDeletePredicate predicate = new NameContainsKeywordsDeletePredicate(
+ Arrays.asList("first".split("\\s+")));
+ DeleteCommand deleteCommand = new DeleteCommand(predicate);
+ String expected = DeleteCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
assertEquals(expected, deleteCommand.toString());
}
@@ -115,6 +145,73 @@ public void toStringMethod() {
private void showNoPerson(Model model) {
model.updateFilteredPersonList(p -> false);
- assertTrue(model.getFilteredPersonList().isEmpty());
+ assertTrue(model.getDisplayPersons().isEmpty());
+ }
+
+ @Test
+ public void execute_emptyList_throwsCommandException() {
+ // Clear the current model's list
+ model.setClientHub(new ClientHub());
+
+ // Attempt to delete a person when the list is empty
+ NameContainsKeywordsDeletePredicate predicate = new NameContainsKeywordsDeletePredicate(
+ Arrays.asList("NonexistentName".split("\\s+")));
+ DeleteCommand deleteCommand = new DeleteCommand(predicate);
+
+ // Expect a CommandException with the person not found message
+ assertCommandFailure(deleteCommand, model, Messages.MESSAGE_PERSON_NOT_FOUND);
}
+
+ @Test
+ public void execute_caseInsensitiveNameMatching_success() {
+ // Get the first person in the unfiltered list
+ Person personToDelete = model.getDisplayPersons().get(INDEX_THIRD_PERSON.getZeroBased() + 1);
+
+ // Create a predicate using a different case
+ NameContainsKeywordsDeletePredicate predicate = new NameContainsKeywordsDeletePredicate(
+ Arrays.asList(personToDelete.getName().fullName.toUpperCase().split("\\s+")));
+
+ // Create the DeleteCommand with the case-insensitive predicate
+ DeleteCommand deleteCommand = new DeleteCommand(predicate);
+
+ // Expected success message
+ String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
+ Messages.format(personToDelete));
+
+ // Create the expected model and delete the person
+ Model expectedModel = new ModelManager(model.getClientHub(), new UserPrefs());
+ expectedModel.deletePerson(personToDelete);
+
+ // Perform the delete operation
+ assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
+ }
+
+ @Test
+ public void execute_multipleMatchingNames_throwsCommandException() {
+ // Get the first person in the list and use a name that could match multiple entries
+ Person personToDelete = model.getDisplayPersons().get(INDEX_FIRST_PERSON.getZeroBased());
+ String name = personToDelete.getName().fullName.split("\\s+")[0];
+
+ // Create a DeleteCommand for the name that could have multiple matches
+ DeleteCommand deleteCommand = new DeleteCommand(new NameContainsKeywordsDeletePredicate(
+ Arrays.asList(name)));
+
+ // Expect a CommandException for vague delete message
+ assertCommandFailureWithNewList(deleteCommand, name, model, Messages.MESSAGE_VAGUE_DELETE);
+ }
+
+ @Test
+ public void execute_personHasReminder_throwsCommandException() {
+ // Get the first person in the list
+ Person personToDelete = model.getDisplayPersons().get(INDEX_SECOND_PERSON.getZeroBased());
+ String name = personToDelete.getName().fullName.split("\\s+")[0];
+
+ // Create a DeleteCommand for the person
+ DeleteCommand deleteCommand = new DeleteCommand(new NameContainsKeywordsDeletePredicate(
+ Arrays.asList(name)));
+
+ // Expect a CommandException for the person having reminders
+ assertCommandFailureWithNewList(deleteCommand, name, model, Messages.MESSAGE_TARGET_DELETE_HAS_REMINDER);
+ }
+
}
diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
index 469dd97daa7..5c68d94cd7f 100644
--- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
@@ -5,22 +5,24 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
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_CLIENT_TYPE_B;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DESCRIPTION_B;
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.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_FOURTH_PERSON;
import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
import org.junit.jupiter.api.Test;
import seedu.address.commons.core.index.Index;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.model.AddressBook;
+import seedu.address.model.ClientHub;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
@@ -33,38 +35,40 @@
*/
public class EditCommandTest {
- private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model model = new ModelManager(getTypicalClientHub(), new UserPrefs());
@Test
public void execute_allFieldsSpecifiedUnfilteredList_success() {
Person editedPerson = new PersonBuilder().build();
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(editedPerson).build();
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor);
+ EditCommand editCommand = new EditCommand(INDEX_FOURTH_PERSON, descriptor);
String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
- expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
+ Model expectedModel = new ModelManager(new ClientHub(model.getClientHub()), new UserPrefs());
+ expectedModel.setPerson(model.getDisplayPersons().get(3), editedPerson);
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@Test
public void execute_someFieldsSpecifiedUnfilteredList_success() {
- Index indexLastPerson = Index.fromOneBased(model.getFilteredPersonList().size());
- Person lastPerson = model.getFilteredPersonList().get(indexLastPerson.getZeroBased());
+ Index indexLastPerson = Index.fromOneBased(model.getDisplayPersons().size());
+ Person lastPerson = model.getDisplayPersons().get(indexLastPerson.getZeroBased());
+ // Doesnt edit Name
PersonBuilder personInList = new PersonBuilder(lastPerson);
- Person editedPerson = personInList.withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withTags(VALID_TAG_HUSBAND).build();
+ Person editedPerson = personInList.withPhone(VALID_PHONE_BOB)
+ .withClientTypes(VALID_CLIENT_TYPE_B).withDescription(VALID_DESCRIPTION_B).build();
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
- .withPhone(VALID_PHONE_BOB).withTags(VALID_TAG_HUSBAND).build();
+ EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder()
+ .withPhone(VALID_PHONE_BOB).withClientTypes(VALID_CLIENT_TYPE_B)
+ .withDescription(VALID_DESCRIPTION_B).build();
EditCommand editCommand = new EditCommand(indexLastPerson, descriptor);
String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
+ Model expectedModel = new ModelManager(new ClientHub(model.getClientHub()), new UserPrefs());
expectedModel.setPerson(lastPerson, editedPerson);
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
@@ -73,11 +77,11 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() {
@Test
public void execute_noFieldSpecifiedUnfilteredList_success() {
EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, new EditPersonDescriptor());
- Person editedPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
+ Person editedPerson = model.getDisplayPersons().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());
+ Model expectedModel = new ModelManager(new ClientHub(model.getClientHub()), new UserPrefs());
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@@ -86,34 +90,34 @@ public void execute_noFieldSpecifiedUnfilteredList_success() {
public void execute_filteredList_success() {
showPersonAtIndex(model, INDEX_FIRST_PERSON);
- Person personInFilteredList = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- Person editedPerson = new PersonBuilder(personInFilteredList).withName(VALID_NAME_BOB).build();
+ Person personInFilteredList = model.getDisplayPersons().get(INDEX_FIRST_PERSON.getZeroBased());
+ Person editedPerson = new PersonBuilder(personInFilteredList).withPhone(VALID_PHONE_BOB).build();
EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON,
- new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build());
+ new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB).build());
String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
- expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
+ Model expectedModel = new ModelManager(new ClientHub(model.getClientHub()), new UserPrefs());
+ expectedModel.setPerson(model.getDisplayPersons().get(0), editedPerson);
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@Test
public void execute_duplicatePersonUnfilteredList_failure() {
- Person firstPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
+ Person firstPerson = model.getDisplayPersons().get(INDEX_FIRST_PERSON.getZeroBased());
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(firstPerson).build();
- EditCommand editCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor);
+ EditCommand editCommand = new EditCommand(INDEX_FOURTH_PERSON, descriptor);
assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON);
}
@Test
public void execute_duplicatePersonFilteredList_failure() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ showPersonAtIndex(model, INDEX_FOURTH_PERSON);
// edit person in filtered list into a duplicate in address book
- Person personInList = model.getAddressBook().getPersonList().get(INDEX_SECOND_PERSON.getZeroBased());
+ Person personInList = model.getClientHub().getPersonList().get(INDEX_SECOND_PERSON.getZeroBased());
EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON,
new EditPersonDescriptorBuilder(personInList).build());
@@ -122,7 +126,7 @@ public void execute_duplicatePersonFilteredList_failure() {
@Test
public void execute_invalidPersonIndexUnfilteredList_failure() {
- Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
+ Index outOfBoundIndex = Index.fromOneBased(model.getDisplayPersons().size() + 1);
EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build();
EditCommand editCommand = new EditCommand(outOfBoundIndex, descriptor);
@@ -138,7 +142,7 @@ 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());
+ assertTrue(outOfBoundIndex.getZeroBased() < model.getClientHub().getPersonList().size());
EditCommand editCommand = new EditCommand(outOfBoundIndex,
new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build());
diff --git a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java b/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
index b17c1f3d5c2..d23a17803ae 100644
--- a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
@@ -6,10 +6,10 @@
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_CLIENT_TYPE_B;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_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 org.junit.jupiter.api.Test;
@@ -52,8 +52,8 @@ public void equals() {
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();
+ // different clientTypes -> returns false
+ editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withClientTypes(VALID_CLIENT_TYPE_B).build();
assertFalse(DESC_AMY.equals(editedAmy));
}
@@ -64,8 +64,10 @@ public void toStringMethod() {
+ 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.getAddress().orElse(null) + ", clientTypes="
+ + editPersonDescriptor.getClientTypes().orElse(null) + ", description="
+ + editPersonDescriptor.getDescription().orElse(null) + ", reminders="
+ + editPersonDescriptor.getReminders().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..f5854e5dfa3 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, false, true);
assertCommandSuccess(new ExitCommand(), model, expectedCommandResult, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/FindAddressCommandTest.java b/src/test/java/seedu/address/logic/commands/FindAddressCommandTest.java
new file mode 100644
index 00000000000..f6ff8dd3a6b
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FindAddressCommandTest.java
@@ -0,0 +1,89 @@
+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.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalPersons.DANIEL;
+import static seedu.address.testutil.TypicalPersons.GEORGE;
+import static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
+
+import java.util.Arrays;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.person.AddressContainsKeywordsPredicate;
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code FindAddressCommand}.
+ */
+public class FindAddressCommandTest {
+ private Model model = new ModelManager(getTypicalClientHub(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalClientHub(), new UserPrefs());
+
+ @Test
+ public void equals() {
+ AddressContainsKeywordsPredicate firstPredicate =
+ new AddressContainsKeywordsPredicate("first");
+ AddressContainsKeywordsPredicate secondPredicate =
+ new AddressContainsKeywordsPredicate("second");
+
+ FindAddressCommand findFirstAddressCommand = new FindAddressCommand(firstPredicate);
+ FindAddressCommand findSecondAddressCommand = new FindAddressCommand(secondPredicate);
+
+ // same object -> returns true
+ assertTrue(findFirstAddressCommand.equals(findFirstAddressCommand));
+
+ // same values -> returns true
+ FindAddressCommand findFirstAddressCommandCopy = new FindAddressCommand(firstPredicate);
+ assertTrue(findFirstAddressCommand.equals(findFirstAddressCommandCopy));
+
+ // different types -> returns false
+ assertFalse(findFirstAddressCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(findFirstAddressCommand.equals(null));
+
+ // different address -> returns false
+ assertFalse(findFirstAddressCommand.equals(findSecondAddressCommand));
+ }
+
+ @Test
+ public void execute_zeroKeywords_noPersonFound() {
+ String expectedMessage = Messages.MESSAGE_ADDRESS_NOT_FOUND;
+ AddressContainsKeywordsPredicate predicate = prepareAddressPredicate(" ");
+ FindAddressCommand command = new FindAddressCommand(predicate);
+ assertCommandFailure(command, model, expectedMessage);
+ }
+
+ @Test
+ public void execute_multipleKeywords_multiplePersonsFound() {
+ String expectedMessage = Messages.getMessagePersonsListedOverview(2);
+ AddressContainsKeywordsPredicate predicate = prepareAddressPredicate("th street");
+ FindAddressCommand command = new FindAddressCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(DANIEL, GEORGE), model.getDisplayPersons());
+ }
+
+ @Test
+ public void toStringMethod() {
+ AddressContainsKeywordsPredicate predicate = new AddressContainsKeywordsPredicate("Tampines");
+ FindAddressCommand findAddressCommand = new FindAddressCommand(predicate);
+ String expected = FindAddressCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
+ assertEquals(expected, findAddressCommand.toString());
+ }
+
+ /**
+ * Parses {@code userInput} into a {@code AddressContainsKeywordsPredicate}.
+ */
+ private AddressContainsKeywordsPredicate prepareAddressPredicate(String userInput) {
+ return new AddressContainsKeywordsPredicate(userInput);
+ }
+}
+
diff --git a/src/test/java/seedu/address/logic/commands/FindClientTypeCommandTest.java b/src/test/java/seedu/address/logic/commands/FindClientTypeCommandTest.java
new file mode 100644
index 00000000000..260b4a0b6e6
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FindClientTypeCommandTest.java
@@ -0,0 +1,135 @@
+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_CLIENT_TYPE_NOT_FOUND;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+import static seedu.address.testutil.TypicalPersons.CARL;
+import static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.person.ClientTypeContainsKeywordsPredicate;
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code FindClientTypeCommand}.
+ */
+public class FindClientTypeCommandTest {
+ private Model model = new ModelManager(getTypicalClientHub(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalClientHub(), new UserPrefs());
+
+ @Test
+ public void equals() {
+ ClientTypeContainsKeywordsPredicate firstPredicate =
+ new ClientTypeContainsKeywordsPredicate(List.of("Investment"));
+ ClientTypeContainsKeywordsPredicate secondPredicate =
+ new ClientTypeContainsKeywordsPredicate(List.of("Healthcare"));
+
+ FindClientTypeCommand findClientTypeFirstCommand = new FindClientTypeCommand(firstPredicate);
+ FindClientTypeCommand findClientTypeSecondCommand = new FindClientTypeCommand(secondPredicate);
+
+ // same object -> returns true
+ assertTrue(findClientTypeFirstCommand.equals(findClientTypeFirstCommand));
+
+ // same values -> returns true
+ FindClientTypeCommand findClientTypeFirstCommandCopy = new FindClientTypeCommand(firstPredicate);
+ assertTrue(findClientTypeFirstCommand.equals(findClientTypeFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(findClientTypeFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(findClientTypeFirstCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(findClientTypeFirstCommand.equals(findClientTypeSecondCommand));
+ }
+
+ @Test
+ public void execute_zeroKeywords_noClientFound() {
+ String expectedMessage = String.format(MESSAGE_CLIENT_TYPE_NOT_FOUND);
+ String userInput = " ";
+ ClientTypeContainsKeywordsPredicate predicate = preparePredicate(userInput);
+ FindClientTypeCommand command = new FindClientTypeCommand(predicate);
+ assertCommandFailure(command, model, expectedMessage);
+ }
+
+ @Test
+ public void execute_singleKeyword_multipleClientsFound() {
+ String expectedMessage = Messages.getMessagePersonsListedOverview(3);
+ ClientTypeContainsKeywordsPredicate predicate = preparePredicate("Investment");
+ FindClientTypeCommand command = new FindClientTypeCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE, BENSON, CARL), model.getDisplayPersons());
+ }
+
+ @Test
+ public void execute_caseInsensitiveKeyword_multipleClientsFound() {
+ String expectedMessage = Messages.getMessagePersonsListedOverview(3);
+ ClientTypeContainsKeywordsPredicate predicate = preparePredicate("inVeStMeNt");
+ FindClientTypeCommand command = new FindClientTypeCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE, BENSON, CARL), model.getDisplayPersons());
+ }
+
+ @Test
+ public void execute_multipleMatchingKeywords_singleClientFound() {
+ String expectedMessage = Messages.getMessagePersonsListedOverview(1);
+ ClientTypeContainsKeywordsPredicate predicate = preparePredicate("Investment Healthcare");
+ FindClientTypeCommand command = new FindClientTypeCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(CARL), model.getDisplayPersons());
+ }
+
+ @Test
+ public void execute_secondWordMatch_returnsCorrectClient() {
+ // Should match person with client type "Investment Plan" when searching just "Plan"
+ String expectedMessage = Messages.getMessagePersonsListedOverview(1);
+ ClientTypeContainsKeywordsPredicate predicate = preparePredicate("Savings");
+ FindClientTypeCommand command = new FindClientTypeCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(BENSON), model.getDisplayPersons());
+ }
+
+ // @Test
+ // public void execute_multipleKeywordsMatchingSingleClientType_singleClientFound() {
+ // String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 1);
+ // ClientTypeContainsKeywordsPredicate predicate = preparePredicate("Insurance Plan");
+ // FindClientTypeCommand command = new FindClientTypeCommand(predicate);
+ // expectedModel.updateFilteredPersonList(predicate);
+ // assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ // assertEquals(Arrays.asList(HARRY), model.getDisplayPersons());
+ // }
+
+
+ @Test
+ public void toStringMethod() {
+ ClientTypeContainsKeywordsPredicate predicate = new ClientTypeContainsKeywordsPredicate(List.of("Investment"));
+ FindClientTypeCommand findClientTypeCommand = new FindClientTypeCommand(predicate);
+ String expected = FindClientTypeCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
+ assertEquals(expected, findClientTypeCommand.toString());
+ }
+
+ /**
+ * Parses {@code userInput} into a {@code ClientTypeContainsKeywordsPredicate}.
+ */
+ private ClientTypeContainsKeywordsPredicate preparePredicate(String userInput) {
+ String[] keywords = userInput.split("\\s+");
+ return new ClientTypeContainsKeywordsPredicate(List.of(keywords));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
index b8b7dbba91a..f69dad196c4 100644
--- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
@@ -3,18 +3,15 @@
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 static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
import java.util.Arrays;
import java.util.Collections;
import org.junit.jupiter.api.Test;
+import seedu.address.logic.Messages;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
@@ -24,8 +21,8 @@
* 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());
+ private Model model = new ModelManager(getTypicalClientHub(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalClientHub(), new UserPrefs());
@Test
public void equals() {
@@ -56,22 +53,12 @@ public void equals() {
@Test
public void execute_zeroKeywords_noPersonFound() {
- String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
+ String expectedMessage = Messages.getMessagePersonsListedOverview(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());
+ assertEquals(Collections.emptyList(), model.getDisplayPersons());
}
@Test
diff --git a/src/test/java/seedu/address/logic/commands/FindNameCommandTest.java b/src/test/java/seedu/address/logic/commands/FindNameCommandTest.java
new file mode 100644
index 00000000000..cc8de2ceeaa
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FindNameCommandTest.java
@@ -0,0 +1,76 @@
+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.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.Messages;
+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 FindNameCommandTest {
+ private Model model = new ModelManager(getTypicalClientHub(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalClientHub(), new UserPrefs());
+
+ @Test
+ public void equals() {
+ NameContainsKeywordsPredicate firstPredicate =
+ new NameContainsKeywordsPredicate(Collections.singletonList("first"));
+ NameContainsKeywordsPredicate secondPredicate =
+ new NameContainsKeywordsPredicate(Collections.singletonList("second"));
+
+ FindNameCommand findFirstCommand = new FindNameCommand(firstPredicate);
+ FindNameCommand findSecondCommand = new FindNameCommand(secondPredicate);
+
+ // same object -> returns true
+ assertTrue(findFirstCommand.equals(findFirstCommand));
+
+ // same values -> returns true
+ FindNameCommand findFirstCommandCopy = new FindNameCommand(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));
+ }
+
+ @Test
+ public void execute_zeroKeywords_noPersonFound() {
+ String expectedMessage = Messages.MESSAGE_PERSON_NOT_FOUND;
+ NameContainsKeywordsPredicate predicate = preparePredicate(" ");
+ FindNameCommand command = new FindNameCommand(predicate);
+ assertCommandFailure(command, model, expectedMessage);
+ }
+
+ @Test
+ public void toStringMethod() {
+ NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Arrays.asList("keyword"));
+ FindNameCommand findCommand = new FindNameCommand(predicate);
+ String expected = FindNameCommand.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+")));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/FindPhoneCommandTest.java b/src/test/java/seedu/address/logic/commands/FindPhoneCommandTest.java
new file mode 100644
index 00000000000..a3e5c911268
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/FindPhoneCommandTest.java
@@ -0,0 +1,89 @@
+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.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalPersons.ELLE;
+import static seedu.address.testutil.TypicalPersons.FIONA;
+import static seedu.address.testutil.TypicalPersons.GEORGE;
+import static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
+
+import java.util.Arrays;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.person.PhoneBeginsWithKeywordPredicate;
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code FindCommand}.
+ */
+public class FindPhoneCommandTest {
+ private Model model = new ModelManager(getTypicalClientHub(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalClientHub(), new UserPrefs());
+
+ @Test
+ public void equals() {
+ PhoneBeginsWithKeywordPredicate firstPredicate =
+ new PhoneBeginsWithKeywordPredicate("9876");
+ PhoneBeginsWithKeywordPredicate secondPredicate =
+ new PhoneBeginsWithKeywordPredicate("9678");
+
+ FindPhoneCommand findPhoneFirstCommand = new FindPhoneCommand(firstPredicate);
+ FindPhoneCommand findPhoneSecondCommand = new FindPhoneCommand(secondPredicate);
+
+ // same object -> returns true
+ assertTrue(findPhoneFirstCommand.equals(findPhoneFirstCommand));
+
+ // same values -> returns true
+ FindPhoneCommand findPhoneFirstCommandCopy = new FindPhoneCommand(firstPredicate);
+ assertTrue(findPhoneFirstCommand.equals(findPhoneFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(findPhoneFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(findPhoneFirstCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(findPhoneFirstCommand.equals(findPhoneSecondCommand));
+ }
+
+ @Test
+ public void execute_zeroKeywords_noPhoneFound() {
+ String expectedMessage = Messages.MESSAGE_PHONE_NOT_FOUND;
+ PhoneBeginsWithKeywordPredicate predicate = preparePredicate(" ");
+ FindPhoneCommand command = new FindPhoneCommand(predicate);
+ assertCommandFailure(command, model, expectedMessage);
+ }
+
+ @Test
+ public void execute_singleKeyword_multiplePersonsFound() {
+ String expectedMessage = Messages.getMessagePersonsListedOverview(3);
+ PhoneBeginsWithKeywordPredicate predicate = preparePredicate("948");
+ FindPhoneCommand command = new FindPhoneCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ELLE, FIONA, GEORGE), model.getDisplayPersons());
+ }
+
+ @Test
+ public void toStringMethod() {
+ PhoneBeginsWithKeywordPredicate predicate = new PhoneBeginsWithKeywordPredicate("keyword");
+ FindPhoneCommand findPhoneCommand = new FindPhoneCommand(predicate);
+ String expected = FindPhoneCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
+ assertEquals(expected, findPhoneCommand.toString());
+ }
+
+ /**
+ * Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}.
+ */
+ private PhoneBeginsWithKeywordPredicate preparePredicate(String userInput) {
+ return new PhoneBeginsWithKeywordPredicate(userInput);
+ }
+}
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/ListCommandTest.java b/src/test/java/seedu/address/logic/commands/ListCommandTest.java
index 435ff1f7275..c4a5ee157f4 100644
--- a/src/test/java/seedu/address/logic/commands/ListCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ListCommandTest.java
@@ -3,7 +3,7 @@
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.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -22,8 +22,8 @@ public class ListCommandTest {
@BeforeEach
public void setUp() {
- model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
- expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ model = new ModelManager(getTypicalClientHub(), new UserPrefs());
+ expectedModel = new ModelManager(model.getClientHub(), new UserPrefs());
}
@Test
diff --git a/src/test/java/seedu/address/logic/commands/SortCommandTest.java b/src/test/java/seedu/address/logic/commands/SortCommandTest.java
new file mode 100644
index 00000000000..84532bcf0f6
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/SortCommandTest.java
@@ -0,0 +1,81 @@
+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.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPersons.ALICEY;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+import static seedu.address.testutil.TypicalPersons.CARL;
+import static seedu.address.testutil.TypicalPersons.DANIEL;
+import static seedu.address.testutil.TypicalPersons.ELLE;
+import static seedu.address.testutil.TypicalPersons.FIONA;
+import static seedu.address.testutil.TypicalPersons.GEORGE;
+import static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
+
+import java.util.Arrays;
+
+import org.junit.jupiter.api.BeforeEach;
+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.NameComparator;
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code SortCommand}.
+ */
+public class SortCommandTest {
+ private Model model;
+ private Model expectedModel;
+
+ @BeforeEach
+ public void setUp() {
+ model = new ModelManager(getTypicalClientHub(), new UserPrefs());
+ expectedModel = new ModelManager(model.getClientHub(), new UserPrefs());
+ }
+
+ @Test
+ public void test_execute() {
+ String expectedMessage = SortCommand.MESSAGE_SUCCESS;
+
+ NameComparator comparator = new NameComparator();
+ SortCommand command = new SortCommand();
+ expectedModel.updateSortedPersonList(comparator);
+
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE, ALICEY, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE),
+ model.getDisplayPersons());
+ }
+
+
+ @Test
+ public void equals() {
+
+ SortCommand sortFirstCommand = new SortCommand();
+ SortCommand sortSecondCommand = new SortCommand();
+
+ // same object -> returns true
+ assertTrue(sortFirstCommand.equals(sortFirstCommand));
+
+ // different types -> returns false
+ assertFalse(sortFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(sortFirstCommand.equals(null));
+
+ // same comparator -> returns true
+ assertTrue(sortFirstCommand.equals(sortSecondCommand));
+ }
+
+ @Test
+ public void toStringMethod() {
+ NameComparator comparator = new NameComparator();
+ SortCommand sortCommand = new SortCommand();
+ String expected = SortCommand.class.getCanonicalName() + "{comparator=" + comparator + "}";
+ assertEquals(expected, sortCommand.toString());
+ }
+
+}
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..0f60594cd56
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/ViewCommandTest.java
@@ -0,0 +1,142 @@
+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_PERSON_LISTED_OVERVIEW_FOR_VIEW;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailureWithNewList;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalPersons.BENSON;
+import static seedu.address.testutil.TypicalPersons.getTypicalClientHub;
+
+import java.util.Arrays;
+import java.util.List;
+
+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 ViewCommand}.
+ */
+public class ViewCommandTest {
+ private Model model = new ModelManager(getTypicalClientHub(), new UserPrefs());
+ private Model expectedModel = new ModelManager(getTypicalClientHub(), new UserPrefs());
+
+ @Test
+ public void equals() {
+ NameContainsKeywordsPredicate firstPredicate =
+ new NameContainsKeywordsPredicate(List.of("Alice"));
+ NameContainsKeywordsPredicate secondPredicate =
+ new NameContainsKeywordsPredicate(List.of("Bob"));
+
+ ViewCommand viewCommandFirstCommand = new ViewCommand(firstPredicate);
+ ViewCommand viewCommandSecondCommand = new ViewCommand(secondPredicate);
+
+ // same object -> returns true
+ assertTrue(viewCommandFirstCommand.equals(viewCommandFirstCommand));
+
+ // same values -> returns true
+ ViewCommand viewCommandFirstCommandCopy = new ViewCommand(firstPredicate);
+ assertTrue(viewCommandFirstCommand.equals(viewCommandFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(viewCommandFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(viewCommandFirstCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(viewCommandFirstCommand.equals(viewCommandSecondCommand));
+ }
+
+ @Test
+ public void execute_singleKeyword_onePersonFound() {
+ CommandResult expectedCommandResult = new CommandResult(
+ String.format(MESSAGE_PERSON_LISTED_OVERVIEW_FOR_VIEW, 1), false, true, false);
+ NameContainsKeywordsPredicate predicate = preparePredicate("Benson Meier");
+ ViewCommand command = new ViewCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedCommandResult, expectedModel);
+ assertEquals(Arrays.asList(BENSON), model.getDisplayPersons());
+ }
+
+ @Test
+ public void execute_partialKeyword_onePersonFound() {
+ CommandResult expectedCommandResult = new CommandResult(
+ String.format(MESSAGE_PERSON_LISTED_OVERVIEW_FOR_VIEW, 1), false, true, false);
+ NameContainsKeywordsPredicate predicate = preparePredicate("Ben");
+ ViewCommand command = new ViewCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedCommandResult, expectedModel);
+ assertEquals(Arrays.asList(BENSON), model.getDisplayPersons());
+ }
+
+ @Test
+ public void execute_multipleSpaces_throwsCommandException() {
+ NameContainsKeywordsPredicate predicate = preparePredicate(" ");
+ ViewCommand command = new ViewCommand(predicate);
+ assertCommandFailure(command, model, ViewCommand.NO_PERSON_FOUND_VIEW_MESSAGE);
+ }
+
+ @Test
+ public void execute_singleKeywordNoPersonFound_throwsCommandException() {
+ NameContainsKeywordsPredicate predicate = preparePredicate("NonExistentName");
+ ViewCommand command = new ViewCommand(predicate);
+ assertCommandFailure(command, model, ViewCommand.NO_PERSON_FOUND_VIEW_MESSAGE);
+ }
+
+ @Test
+ public void execute_singleKeywordTwoPersonFound_throwsCommandException() {
+ NameContainsKeywordsPredicate predicate = preparePredicate("Alice");
+ ViewCommand command = new ViewCommand(predicate);
+ assertCommandFailureWithNewList(command, "Alice", model, String.format(
+ MESSAGE_PERSON_LISTED_OVERVIEW_FOR_VIEW + ViewCommand.MORE_THAN_ONE_PERSON_VIEW_MESSAGE, 2));
+ }
+
+ /**
+ * Tests that ViewCommand throws a CommandException when the surname prefix search ("K")
+ * matches multiple people in the address book (e.g., "Fiona Kunz" and "Carl Kurz").
+ * Since the prefix of ths surname of Fiona Kunz and Carl Kurz is "K", the search will return both of them.
+ */
+ @Test
+ public void execute_surnameKeywordTwoPersonFound_throwsCommandException() {
+ NameContainsKeywordsPredicate predicate = preparePredicate("K");
+ ViewCommand command = new ViewCommand(predicate);
+ assertCommandFailureWithNewList(command, "K", model, String.format(
+ MESSAGE_PERSON_LISTED_OVERVIEW_FOR_VIEW + ViewCommand.MORE_THAN_ONE_PERSON_VIEW_MESSAGE, 2));
+ }
+
+ @Test
+ public void execute_mixedCaseFullName_success() {
+ CommandResult expectedCommandResult = new CommandResult(
+ String.format(MESSAGE_PERSON_LISTED_OVERVIEW_FOR_VIEW, 1), false, true, false);
+ NameContainsKeywordsPredicate predicate = preparePredicate("bEnSoN mEiEr");
+ ViewCommand command = new ViewCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedCommandResult, expectedModel);
+ assertEquals(Arrays.asList(BENSON), model.getDisplayPersons());
+ }
+
+
+ @Test
+ public void toStringMethod() {
+ NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(List.of("Alice"));
+ ViewCommand findClientTypeCommand = new ViewCommand(predicate);
+ String expected = ViewCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
+ assertEquals(expected, findClientTypeCommand.toString());
+ }
+
+ /**
+ * Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}.
+ */
+ private NameContainsKeywordsPredicate preparePredicate(String userInput) {
+ // Split the input string by whitespaces
+ String[] keywords = userInput.split("\\s+");
+ return new NameContainsKeywordsPredicate(List.of(keywords));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/reminder/AddReminderCommandTest.java b/src/test/java/seedu/address/logic/commands/reminder/AddReminderCommandTest.java
new file mode 100644
index 00000000000..08aa9c9d7a3
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/reminder/AddReminderCommandTest.java
@@ -0,0 +1,124 @@
+package seedu.address.logic.commands.reminder;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalReminders.getTypicalClientHub;
+
+import java.time.LocalDateTime;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
+import seedu.address.model.ClientHub;
+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.reminder.Reminder;
+import seedu.address.model.reminder.ReminderDescription;
+import seedu.address.testutil.PersonBuilder;
+
+
+public class AddReminderCommandTest {
+ private ClientHub clientHub = getTypicalClientHub();
+ private Model model = new ModelManager(clientHub, new UserPrefs());
+
+ @Test
+ public void execute_validPerson_success() {
+ // Setup a valid person and reminder
+ Person personToAddReminder = model.getClientHub().getPersonList().get(Index.fromZeroBased(0).getZeroBased());
+ ReminderDescription reminderDescription = new ReminderDescription("New Year's Eve");
+
+ Reminder reminderToAdd = new Reminder(personToAddReminder.getName().fullName,
+ LocalDateTime.of(2024, 11, 5, 14, 0), reminderDescription);
+
+ // Create AddReminderCommand with the valid reminder
+ AddReminderCommand addReminderCommand = new AddReminderCommand(reminderToAdd);
+
+ // Expected success message after the reminder is added
+ String expectedMessage = String.format(AddReminderCommand.MESSAGE_SUCCESS,
+ Messages.format(reminderToAdd));
+
+ // Create expected model and perform the add operation
+ Model expectedModel = new ModelManager(model.getClientHub(), new UserPrefs());
+ Person personCopy = expectedModel.getClientHub().getPersonList().get(Index.fromZeroBased(0).getZeroBased());
+ personCopy.addReminder(reminderToAdd);
+
+ // Verify the expected model and actual model match after executing the command
+ assertCommandSuccess(addReminderCommand, model, expectedMessage, expectedModel);
+ }
+
+ @Test
+ public void execute_nonexistentPerson_throwsCommandException() {
+ // Setup a reminder with a nonexistent person name
+ Reminder nonexistentReminder = new Reminder("Nonexistent Person",
+ LocalDateTime.of(2024, 11, 5, 14, 0),
+ new ReminderDescription("New Year's Eve"));
+
+ // Create AddReminderCommand with the invalid reminder
+ AddReminderCommand addReminderCommand = new AddReminderCommand(nonexistentReminder);
+
+ // Execute the command and expect failure
+ assertCommandFailure(addReminderCommand, model, AddReminderCommand.MESSAGE_NONEXISTENT_PERSON);
+ }
+
+ @Test
+ public void execute_multipleMatchingPersons_throwsCommandException() {
+ // Initialize the model with an empty ClientHub and UserPrefs
+ Model model = new ModelManager(new ClientHub(), new UserPrefs());
+
+ // Create two persons with similar names
+ Person alice = new PersonBuilder().withName("Alice").build();
+ Person alice2 = new PersonBuilder().withName("Alicee").build();
+
+ // Add both persons to the model
+ model.addPerson(alice);
+ model.addPerson(alice2);
+
+ // Setup a reminder with an ambiguous name that matches multiple persons
+ Reminder ambiguousReminder = new Reminder("Alice",
+ LocalDateTime.of(2024, 11, 5, 14, 0),
+ new ReminderDescription("New Year's Eve"));
+
+ // Create AddReminderCommand with the ambiguous reminder
+ AddReminderCommand addReminderCommand = new AddReminderCommand(ambiguousReminder);
+
+ // Execute the command and expect failure due to multiple matches
+ assertCommandFailure(addReminderCommand, model, AddReminderCommand.MESSAGE_MORE_THAN_ONE_PERSON);
+ }
+
+ @Test
+ public void equals_sameObjectAndValues_returnsTrue() {
+ // Arrange: Create identical reminders and commands
+ Reminder firstReminder = new Reminder("John Doe",
+ LocalDateTime.of(2024, 12, 31, 23, 59),
+ new ReminderDescription("New Year's Eve"));
+ AddReminderCommand addFirstCommand = new AddReminderCommand(firstReminder);
+
+ // Positive test case: same object -> returns true
+ assertTrue(addFirstCommand.equals(addFirstCommand));
+
+ // Positive test case: different object, same values -> returns true
+ AddReminderCommand addFirstCommandCopy = new AddReminderCommand(firstReminder);
+ assertTrue(addFirstCommand.equals(addFirstCommandCopy));
+ }
+ @Test
+ public void toString_validAddReminderCommand_correctStringRepresentation() {
+ // Create a Reminder object with sample data
+ Reminder reminder = new Reminder("John Doe",
+ LocalDateTime.of(2021, 12, 31, 23, 59),
+ new ReminderDescription("New Year's Eve"));
+
+ // Create an AddReminderCommand with the reminder
+ AddReminderCommand addReminderCommand = new AddReminderCommand(reminder);
+
+ // Define the expected string representation
+ String expectedString = "AddReminderCommand {toAdd=" + reminder + "}";
+
+ // Verify that the toString output matches the expected string
+ assertEquals(expectedString, addReminderCommand.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/reminder/DeleteReminderCommandTest.java b/src/test/java/seedu/address/logic/commands/reminder/DeleteReminderCommandTest.java
new file mode 100644
index 00000000000..a37cb82a595
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/reminder/DeleteReminderCommandTest.java
@@ -0,0 +1,96 @@
+package seedu.address.logic.commands.reminder;
+
+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.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_REMINDER;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static seedu.address.testutil.TypicalReminders.getTypicalClientHub;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
+import seedu.address.model.ClientHub;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.reminder.Reminder;
+
+
+public class DeleteReminderCommandTest {
+ private ClientHub clientHub = getTypicalClientHub();
+ private Model model = new ModelManager(clientHub, new UserPrefs());
+
+ @Test
+ public void execute_validIndexUnfilteredList_success() {
+ // Retrieve the reminder to delete based on the first index of the unfiltered list
+ Reminder reminderToDelete = model.getDisplayReminders().get(INDEX_FIRST_REMINDER.getZeroBased());
+
+ // Create the DeleteReminderCommand using the index
+ DeleteReminderCommand deleteReminderCommand = new DeleteReminderCommand(INDEX_FIRST_REMINDER);
+
+ // Expected success message after the reminder is deleted
+ String expectedMessage = String.format(DeleteReminderCommand.MESSAGE_DELETE_REMINDER_SUCCESS,
+ Messages.format(reminderToDelete));
+
+ // Create the expected model and perform the delete operation on it
+ ModelManager expectedModel = new ModelManager(model.getClientHub(), new UserPrefs());
+ expectedModel.deleteReminder(reminderToDelete);
+
+ // Perform the command and verify that the expected model and actual model match
+ assertCommandSuccess(deleteReminderCommand, model, expectedMessage, expectedModel);
+ }
+
+ @Test
+ public void execute_invalidIndexUnfilteredList_throwsCommandException() {
+ Index outOfBoundIndex = Index.fromOneBased(model.getDisplayRemindersListSize() + 1);
+ DeleteReminderCommand deleteCommand = new DeleteReminderCommand(outOfBoundIndex);
+ assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_REMINDER_DISPLAYED_INDEX);
+ }
+
+ @Test
+ public void execute_validIndexFilteredList_success() {
+ //showReminderAtIndex(model, INDEX_FIRST_REMINDER);
+ Reminder reminderToDelete = model.getDisplayReminders().get(INDEX_FIRST_PERSON.getZeroBased());
+ DeleteReminderCommand deleteCommand = new DeleteReminderCommand(INDEX_FIRST_PERSON);
+
+ String expectedMessage = String.format(DeleteReminderCommand.MESSAGE_DELETE_REMINDER_SUCCESS,
+ Messages.format(reminderToDelete));
+
+ Model expectedModel = new ModelManager(model.getClientHub(), new UserPrefs());
+ expectedModel.deleteReminder(reminderToDelete);
+
+ assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
+ }
+
+ @Test
+ public void equals() {
+ DeleteReminderCommand deleteFirstCommand = new DeleteReminderCommand(INDEX_FIRST_PERSON);
+ DeleteReminderCommand deleteSecondCommand = new DeleteReminderCommand(INDEX_SECOND_PERSON);
+
+ // same object -> returns true
+ assertTrue(deleteFirstCommand.equals(deleteFirstCommand));
+
+ DeleteReminderCommand deleteFirstCommandCopy = new DeleteReminderCommand(INDEX_FIRST_PERSON);
+ assertTrue(deleteFirstCommand.equals(deleteFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(deleteFirstCommand.equals(1));
+ // null -> returns false
+ assertFalse(deleteFirstCommand.equals(null));
+ // different person -> returns false
+ assertFalse(deleteFirstCommand.equals(deleteSecondCommand));
+ }
+
+ @Test
+ public void toStringMethod() {
+ Index targetIndex = Index.fromOneBased(1);
+ DeleteReminderCommand deleteCommand = new DeleteReminderCommand(targetIndex);
+ String expected = DeleteReminderCommand.class.getCanonicalName() + "{targetIndex=" + targetIndex + "}";
+ assertEquals(expected, deleteCommand.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/reminder/EditReminderCommandTest.java b/src/test/java/seedu/address/logic/commands/reminder/EditReminderCommandTest.java
new file mode 100644
index 00000000000..a9058ed7e1c
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/reminder/EditReminderCommandTest.java
@@ -0,0 +1,89 @@
+package seedu.address.logic.commands.reminder;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static seedu.address.logic.commands.reminder.EditReminderCommand.MESSAGE_REMINDER_NOT_EDITED;
+
+import java.time.LocalDateTime;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.reminder.Reminder;
+import seedu.address.model.reminder.ReminderDescription;
+import seedu.address.model.util.SampleDataUtil;
+
+/**
+ * Contains integration tests (interaction with the Model) and unit tests for EditReminderCommand.
+ */
+public class EditReminderCommandTest {
+
+ private Model model;
+ private Reminder originalReminder;
+ private Reminder editedReminder;
+
+ @BeforeEach
+ public void setUp() {
+ model = new ModelManager(SampleDataUtil.getSampleClientHub(), new UserPrefs());
+ originalReminder = new Reminder("Jeremy Sim", LocalDateTime.of(2022, 1, 1, 0, 0),
+ new ReminderDescription("Initial reminder"));
+ model.addReminder(originalReminder);
+
+ editedReminder = new Reminder("Jeremy Sim", LocalDateTime.of(2022, 1, 2, 12, 0),
+ new ReminderDescription("Edited reminder"));
+ }
+
+ @Test
+ public void execute_allFieldsSpecified_success() throws Exception {
+ EditReminderCommand.EditReminderFields editReminderFields = new EditReminderCommand.EditReminderFields();
+ editReminderFields.setDateTime(editedReminder.getDateTime());
+ editReminderFields.setDescription(editedReminder.getDescription());
+
+ EditReminderCommand command = new EditReminderCommand(Index.fromZeroBased(0), editReminderFields);
+ command.execute(model);
+ assertEquals(editedReminder, model.getDisplayReminders().get(0));
+ }
+
+
+ @Test
+ public void execute_noFieldsSpecified_throwsCommandException() {
+ // Create EditReminderFields with no fields specified
+ EditReminderCommand.EditReminderFields editReminderFields = new EditReminderCommand.EditReminderFields();
+
+ // Create an EditReminderCommand with an index and the empty EditReminderFields
+ EditReminderCommand command = new EditReminderCommand(Index.fromZeroBased(0), editReminderFields);
+
+ // Execute command and expect CommandException due to no fields being edited
+ assertThrows(CommandException.class, () -> command.execute(model),
+ EditReminderCommand.MESSAGE_REMINDER_NOT_EDITED);
+ }
+
+
+ @Test
+ public void execute_duplicateReminder_throwsCommandException() {
+ model.addReminder(editedReminder);
+ EditReminderCommand.EditReminderFields editReminderFields = new EditReminderCommand.EditReminderFields();
+ editReminderFields.setDateTime(editedReminder.getDateTime());
+ editReminderFields.setDescription(editedReminder.getDescription());
+
+ EditReminderCommand command = new EditReminderCommand(Index.fromZeroBased(1), editReminderFields);
+
+ assertThrows(CommandException.class, () -> command.execute(model), MESSAGE_REMINDER_NOT_EDITED);
+ }
+
+ @Test
+ public void execute_invalidReminderIndex_throwsCommandException() {
+ EditReminderCommand.EditReminderFields editReminderFields = new EditReminderCommand.EditReminderFields();
+ editReminderFields.setDateTime(editedReminder.getDateTime());
+ editReminderFields.setDescription(editedReminder.getDescription());
+
+ EditReminderCommand command = new EditReminderCommand(Index.fromZeroBased(10), editReminderFields);
+
+ assertThrows(CommandException.class, () -> command.execute(model), "Invalid reminder index.");
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/reminder/ReminderCommandTestUtil.java b/src/test/java/seedu/address/logic/commands/reminder/ReminderCommandTestUtil.java
new file mode 100644
index 00000000000..85a86b67c05
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/reminder/ReminderCommandTestUtil.java
@@ -0,0 +1,34 @@
+package seedu.address.logic.commands.reminder;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import seedu.address.model.reminder.Reminder;
+import seedu.address.model.reminder.ReminderDescription;
+
+
+/**
+ * Contains helper methods for testing reminder commands.
+ */
+public class ReminderCommandTestUtil {
+
+ // Reminder for Alice Pauline (used in EditCommandTest)
+ public static final String DEFAULT_REMINDER_TIME = "2024-10-10 11:11";
+ public static final String DEFAULT_REMINDER_DESCRIPTION = "Reminder 1";
+ public static final Reminder DEFAULT_REMINDER = new Reminder("Alice Pauline",
+ LocalDateTime.parse(DEFAULT_REMINDER_TIME, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
+ new ReminderDescription(DEFAULT_REMINDER_DESCRIPTION));
+ public static final Set DEFAULT_REMINDER_SET = new HashSet<>(Collections.singleton(DEFAULT_REMINDER));
+
+ // Reminder for Bob Charlie (used in EditCommandTest)
+ public static final String DEFAULT_REMINDER_TIME_2 = "2024-10-10 11:11";
+ public static final String DEFAULT_REMINDER_DESCRIPTION_2 = "Reminder 2";
+ public static final Reminder DEFAULT_REMINDER_2 = new Reminder("Benson Meier",
+ LocalDateTime.parse(DEFAULT_REMINDER_TIME_2, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
+ new ReminderDescription(DEFAULT_REMINDER_DESCRIPTION_2));
+ public static final Set DEFAULT_REMINDER_SET_2 = new HashSet<>(Collections.singleton(DEFAULT_REMINDER_2));
+
+}
diff --git a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
index 5bc11d3cdaa..4fec4f49c5e 100644
--- a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
@@ -3,46 +3,52 @@
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.CLIENT_TYPE_DESC_A;
+import static seedu.address.logic.commands.CommandTestUtil.CLIENT_TYPE_DESC_B;
+import static seedu.address.logic.commands.CommandTestUtil.DESCRIPTION_DESC_A;
+import static seedu.address.logic.commands.CommandTestUtil.DESCRIPTION_DESC_B;
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.INVALID_ADDRESS_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_CLIENT_TYPE_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_DESCRIPTION_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.NAME_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.VALID_ADDRESS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_CLIENT_TYPE_A;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_CLIENT_TYPE_B;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DESCRIPTION_A;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DESCRIPTION_B;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_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_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalPersons.AMY;
import static seedu.address.testutil.TypicalPersons.BOB;
import org.junit.jupiter.api.Test;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.AddCommand;
+import seedu.address.model.clienttype.ClientType;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Description;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Person;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
import seedu.address.testutil.PersonBuilder;
public class AddCommandParserTest {
@@ -50,25 +56,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).withClientTypes(VALID_CLIENT_TYPE_A)
+ .withDescription(VALID_DESCRIPTION_B).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));
+ + ADDRESS_DESC_BOB + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_B, new AddCommand(expectedPerson));
- // multiple tags - all accepted
- Person expectedPersonMultipleTags = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND, VALID_TAG_HUSBAND)
+ // multiple client type - all accepted
+ Person expectedPersonMultipleClientTypes = new PersonBuilder(BOB)
+ .withClientTypes(VALID_CLIENT_TYPE_A, VALID_CLIENT_TYPE_B)
+ .withDescription(VALID_DESCRIPTION_B)
.build();
assertParseSuccess(parser,
- NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND,
- new AddCommand(expectedPersonMultipleTags));
+ NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
+ + CLIENT_TYPE_DESC_B + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_B,
+ new AddCommand(expectedPersonMultipleClientTypes));
}
@Test
- public void parse_repeatedNonTagValue_failure() {
+ public void parse_repeatedNonClientTypeValue_failure() {
String validExpectedPersonString = NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND;
+ + ADDRESS_DESC_BOB + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_B;
// multiple names
assertParseFailure(parser, NAME_DESC_AMY + validExpectedPersonString,
@@ -89,8 +99,10 @@ public void parse_repeatedNonTagValue_failure() {
// multiple fields repeated
assertParseFailure(parser,
validExpectedPersonString + PHONE_DESC_AMY + EMAIL_DESC_AMY + NAME_DESC_AMY + ADDRESS_DESC_AMY
+ + DESCRIPTION_DESC_A
+ validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME, PREFIX_ADDRESS, PREFIX_EMAIL, PREFIX_PHONE));
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME, PREFIX_ADDRESS, PREFIX_EMAIL,
+ PREFIX_PHONE, PREFIX_DESCRIPTION));
// invalid value followed by valid value
@@ -110,6 +122,11 @@ public void parse_repeatedNonTagValue_failure() {
assertParseFailure(parser, INVALID_ADDRESS_DESC + validExpectedPersonString,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_ADDRESS));
+
+ // invalid description
+ assertParseFailure(parser, INVALID_DESCRIPTION_DESC + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_DESCRIPTION));
+
// valid value followed by invalid value
// invalid name
@@ -127,70 +144,89 @@ public void parse_repeatedNonTagValue_failure() {
// invalid address
assertParseFailure(parser, validExpectedPersonString + INVALID_ADDRESS_DESC,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_ADDRESS));
- }
- @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,
- new AddCommand(expectedPerson));
+ // invalid description
+ assertParseFailure(parser, validExpectedPersonString + INVALID_DESCRIPTION_DESC,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_DESCRIPTION));
}
@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, PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + CLIENT_TYPE_DESC_A
+ + DESCRIPTION_DESC_A + VALID_NAME_BOB,
+ "The following field for add command is missing: n/NAME");
// 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 + ADDRESS_DESC_BOB + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_A,
+ "The following field for add command is missing: p/PHONE");
// 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
+ + ADDRESS_DESC_BOB + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_A,
+ "The following field for add command is missing: e/EMAIL");
// 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
+ + VALID_ADDRESS_BOB + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_A,
+ "The following field for add command is missing: a/ADDRESS");
+
+ // missing description prefix
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
+ + ADDRESS_DESC_BOB + CLIENT_TYPE_DESC_A + VALID_DESCRIPTION_A,
+ "The following field for add command is missing: d/DESCRIPTION");
+
+ // missing client type prefix
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
+ + ADDRESS_DESC_BOB + VALID_CLIENT_TYPE_A + DESCRIPTION_DESC_A,
+ "The following field for add command is missing: c/CLIENT_TYPE");
// 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_ADDRESS_BOB + VALID_CLIENT_TYPE_A + VALID_DESCRIPTION_A,
+ "The following fields for add command are missing: n/NAME a/ADDRESS p/PHONE "
+ + "e/EMAIL c/CLIENT_TYPE d/DESCRIPTION");
}
@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);
+ + CLIENT_TYPE_DESC_B + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_A, 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);
+ + CLIENT_TYPE_DESC_B + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_A, 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);
+ + CLIENT_TYPE_DESC_B + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_A, Email.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);
+ + CLIENT_TYPE_DESC_B + CLIENT_TYPE_DESC_A + VALID_CLIENT_TYPE_A
+ + DESCRIPTION_DESC_A, Address.MESSAGE_CONSTRAINTS);
+
+ // invalid client type
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
+ + INVALID_CLIENT_TYPE_DESC + VALID_CLIENT_TYPE_A + VALID_CLIENT_TYPE_A
+ + DESCRIPTION_DESC_A, ClientType.MESSAGE_CONSTRAINTS);
- // invalid tag
+ // invalid description
assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + INVALID_TAG_DESC + VALID_TAG_FRIEND, Tag.MESSAGE_CONSTRAINTS);
+ + CLIENT_TYPE_DESC_B + CLIENT_TYPE_DESC_A + INVALID_DESCRIPTION_DESC, Description.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
+ + INVALID_ADDRESS_DESC + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_B,
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,
+ + ADDRESS_DESC_BOB + CLIENT_TYPE_DESC_B + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_A,
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
deleted file mode 100644
index 5a1ab3dbc0c..00000000000
--- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-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.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-
-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.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.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
-import seedu.address.testutil.PersonBuilder;
-import seedu.address.testutil.PersonUtil;
-
-public class AddressBookParserTest {
-
- private final AddressBookParser parser = new AddressBookParser();
-
- @Test
- public void parseCommand_add() throws Exception {
- Person person = new PersonBuilder().build();
- AddCommand command = (AddCommand) parser.parseCommand(PersonUtil.getAddCommand(person));
- assertEquals(new AddCommand(person), command);
- }
-
- @Test
- public void parseCommand_clear() throws Exception {
- assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD) instanceof ClearCommand);
- assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD + " 3") instanceof ClearCommand);
- }
-
- @Test
- public void parseCommand_delete() throws Exception {
- DeleteCommand command = (DeleteCommand) parser.parseCommand(
- DeleteCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased());
- assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), command);
- }
-
- @Test
- public void parseCommand_edit() throws Exception {
- Person person = new PersonBuilder().build();
- 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);
- assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD + " 3") instanceof ExitCommand);
- }
-
- @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);
- }
-
- @Test
- public void parseCommand_help() throws Exception {
- assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD) instanceof HelpCommand);
- assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD + " 3") instanceof HelpCommand);
- }
-
- @Test
- public void parseCommand_list() throws Exception {
- assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD) instanceof ListCommand);
- assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand);
- }
-
- @Test
- public void parseCommand_unrecognisedInput_throwsParseException() {
- assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), ()
- -> parser.parseCommand(""));
- }
-
- @Test
- public void parseCommand_unknownCommand_throwsParseException() {
- assertThrows(ParseException.class, MESSAGE_UNKNOWN_COMMAND, () -> parser.parseCommand("unknownCommand"));
- }
-}
diff --git a/src/test/java/seedu/address/logic/parser/ArgumentTokenizerTest.java b/src/test/java/seedu/address/logic/parser/ArgumentTokenizerTest.java
index c97308935f5..b8a5a183028 100644
--- a/src/test/java/seedu/address/logic/parser/ArgumentTokenizerTest.java
+++ b/src/test/java/seedu/address/logic/parser/ArgumentTokenizerTest.java
@@ -55,7 +55,7 @@ private void assertArgumentAbsent(ArgumentMultimap argMultimap, Prefix prefix) {
@Test
public void tokenize_noPrefixes_allTakenAsPreamble() {
- String argsString = " some random string /t tag with leading and trailing spaces ";
+ String argsString = " some random string /c client type with leading and trailing spaces ";
ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(argsString);
// Same string expected as preamble, but leading/trailing spaces should be trimmed
diff --git a/src/test/java/seedu/address/logic/parser/ClientHubParserTest.java b/src/test/java/seedu/address/logic/parser/ClientHubParserTest.java
new file mode 100644
index 00000000000..47950f9bebf
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/ClientHubParserTest.java
@@ -0,0 +1,206 @@
+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.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+
+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.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.FindAddressCommand;
+import seedu.address.logic.commands.FindClientTypeCommand;
+import seedu.address.logic.commands.FindNameCommand;
+import seedu.address.logic.commands.FindPhoneCommand;
+import seedu.address.logic.commands.HelpCommand;
+import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.SortCommand;
+import seedu.address.logic.commands.ViewCommand;
+import seedu.address.logic.commands.reminder.DeleteReminderCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.AddressContainsKeywordsPredicate;
+import seedu.address.model.person.ClientTypeContainsKeywordsPredicate;
+import seedu.address.model.person.NameContainsKeywordsDeletePredicate;
+import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.Person;
+import seedu.address.model.person.PhoneBeginsWithKeywordPredicate;
+import seedu.address.testutil.EditPersonDescriptorBuilder;
+import seedu.address.testutil.PersonBuilder;
+import seedu.address.testutil.PersonUtil;
+import seedu.address.testutil.TypicalPersons;
+
+public class ClientHubParserTest {
+
+ private final ClientHubParser parser = new ClientHubParser();
+
+ @Test
+ public void parseCommand_add() throws Exception {
+ Person person = new PersonBuilder().build();
+ AddCommand command = (AddCommand) parser.parseCommand(PersonUtil.getAddCommand(person));
+ assertEquals(new AddCommand(person), command);
+ }
+
+ @Test
+ public void parseShortCommand_add() throws Exception {
+ Person person = new PersonBuilder().build();
+ AddCommand command = (AddCommand) parser.parseCommand(PersonUtil.getAddShortCommand(person));
+ assertEquals(new AddCommand(person), command);
+ }
+
+ @Test
+ public void parseCommand_clear() throws Exception {
+ assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD) instanceof ClearCommand);
+ assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD + " 3") instanceof ClearCommand);
+ }
+
+ @Test
+ public void parseCommand_delete() throws Exception {
+ DeleteCommand command = (DeleteCommand) parser.parseCommand(
+ DeleteCommand.COMMAND_WORD + " " + TypicalPersons.ALICE.getName().fullName);
+ assertEquals(new DeleteCommand(new
+ NameContainsKeywordsDeletePredicate(
+ Arrays.asList(TypicalPersons.ALICE.getName().fullName.split("\\s+")))), command);
+ }
+
+ @Test
+ public void parseShortCommand_delete() throws Exception {
+ DeleteCommand command = (DeleteCommand) parser.parseCommand(
+ DeleteCommand.SHORT_COMMAND_WORD + " " + TypicalPersons.ALICE.getName().fullName);
+ assertEquals(new DeleteCommand(new
+ NameContainsKeywordsDeletePredicate(
+ Arrays.asList(TypicalPersons.ALICE.getName().fullName.split("\\s+")))), command);
+ }
+
+ @Test
+ public void parseCommand_edit() throws Exception {
+ Person person = new PersonBuilder().build();
+ 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);
+ assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD + " 3") instanceof ExitCommand);
+ }
+
+ @Test
+ public void parseCommand_find() throws Exception {
+ List keywords = Arrays.asList("foo", "bar", "baz");
+ FindNameCommand command = (FindNameCommand) parser.parseCommand(
+ FindNameCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" ")));
+ assertEquals(new FindNameCommand(new NameContainsKeywordsPredicate(keywords)), command);
+ }
+
+ @Test
+ public void parseCommand_help() throws Exception {
+ assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD) instanceof HelpCommand);
+ assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD + " 3") instanceof HelpCommand);
+ }
+
+ @Test
+ public void parseCommand_list() throws Exception {
+ assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD) instanceof ListCommand);
+ assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand);
+ }
+
+ @Test
+ public void parseshortCommand_list() throws Exception {
+ assertTrue(parser.parseCommand(ListCommand.SHORT_COMMAND_WORD) instanceof ListCommand);
+ assertTrue(parser.parseCommand(ListCommand.SHORT_COMMAND_WORD + " 3") instanceof ListCommand);
+ }
+
+ @Test
+ public void parseCommand_findPhone() throws Exception {
+ String keyword = "9876";
+ FindPhoneCommand command = (FindPhoneCommand) parser.parseCommand(
+ FindPhoneCommand.COMMAND_WORD + " " + keyword);
+ assertEquals(new FindPhoneCommand(new PhoneBeginsWithKeywordPredicate(keyword)), command);
+ }
+
+ @Test
+ public void parseCommand_findAddress() throws Exception {
+ String keywords = "Tampines";
+ FindAddressCommand command = (FindAddressCommand) parser.parseCommand(
+ FindAddressCommand.COMMAND_WORD + " " + keywords);
+ assertEquals(new FindAddressCommand(new AddressContainsKeywordsPredicate(keywords)), command);
+ }
+
+ @Test
+ public void parseCommand_findClientType() throws Exception {
+ String keyword = "Investment";
+ FindClientTypeCommand command = (FindClientTypeCommand) parser.parseCommand(
+ FindClientTypeCommand.COMMAND_WORD + " " + keyword);
+ assertEquals(new FindClientTypeCommand(new ClientTypeContainsKeywordsPredicate(List.of(keyword))), command);
+ }
+
+ @Test
+ public void parseCommand_sort() throws Exception {
+ String criteria = "n/";
+ SortCommand command = (SortCommand) parser.parseCommand(
+ SortCommand.COMMAND_WORD + " " + criteria);
+ assertEquals(new SortCommand(), command);
+
+ SortCommand shortCommand = (SortCommand) parser.parseCommand(
+ SortCommand.SHORT_COMMAND_WORD + " " + criteria);
+ assertEquals(new SortCommand(), command);
+ }
+
+ @Test
+ public void parseCommand_viewCommand() throws Exception {
+ String keyword = "Alice";
+ ViewCommand command = (ViewCommand) parser.parseCommand(
+ ViewCommand.COMMAND_WORD + " " + keyword);
+ assertEquals(new ViewCommand(new NameContainsKeywordsPredicate(List.of(keyword))), command);
+ }
+
+ @Test
+ public void parseShortCommand_viewCommand() throws Exception {
+ String keyword = "Alice";
+ ViewCommand command = (ViewCommand) parser.parseCommand(
+ ViewCommand.SHORT_COMMAND_WORD + " " + keyword);
+ assertEquals(new ViewCommand(new NameContainsKeywordsPredicate(List.of(keyword))), command);
+ }
+
+ @Test
+ public void parseCommand_reminderDeleteCommand() throws Exception {
+ String keyword = "1";
+ DeleteReminderCommand command = (DeleteReminderCommand) parser.parseCommand(
+ DeleteReminderCommand.COMMAND_WORD + " " + keyword);
+ assertEquals(new DeleteReminderCommand(INDEX_FIRST_PERSON), command);
+ }
+
+ @Test
+ public void parseShortCommand_reminderDeleteCommand() throws Exception {
+ String keyword = "1";
+ DeleteReminderCommand command = (DeleteReminderCommand) parser.parseCommand(
+ DeleteReminderCommand.COMMAND_WORD_SHORT + " " + keyword);
+ assertEquals(new DeleteReminderCommand(INDEX_FIRST_PERSON), command);
+ }
+
+
+
+ @Test
+ public void parseCommand_unrecognisedInput_throwsParseException() {
+ assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), ()
+ -> parser.parseCommand(""));
+ }
+
+ @Test
+ public void parseCommand_unknownCommand_throwsParseException() {
+ assertThrows(ParseException.class, MESSAGE_UNKNOWN_COMMAND, () -> parser.parseCommand("unknownCommand"));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
index 6a40e14a649..6fa17a26ef5 100644
--- a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
@@ -3,11 +3,13 @@
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 static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+
+import java.util.Arrays;
import org.junit.jupiter.api.Test;
import seedu.address.logic.commands.DeleteCommand;
+import seedu.address.model.person.NameContainsKeywordsDeletePredicate;
/**
* As we are only doing white-box testing, our test cases do not cover path variations
@@ -22,11 +24,14 @@ public class DeleteCommandParserTest {
@Test
public void parse_validArgs_returnsDeleteCommand() {
- assertParseSuccess(parser, "1", new DeleteCommand(INDEX_FIRST_PERSON));
+ assertParseSuccess(parser, "Alice",
+ new DeleteCommand(new NameContainsKeywordsDeletePredicate(
+ Arrays.asList("Alice".split("\\s+")))));
}
@Test
public void parse_invalidArgs_throwsParseException() {
- assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, "", String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
}
+
}
diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
index cc7175172d4..ec63f2072f4 100644
--- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
@@ -3,29 +3,34 @@
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.CLIENT_TYPE_DESC_A;
+import static seedu.address.logic.commands.CommandTestUtil.CLIENT_TYPE_DESC_B;
+import static seedu.address.logic.commands.CommandTestUtil.DESCRIPTION_DESC_A;
+import static seedu.address.logic.commands.CommandTestUtil.DESCRIPTION_DESC_B;
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.INVALID_ADDRESS_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_CLIENT_TYPE_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_DESCRIPTION_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.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.VALID_ADDRESS_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_CLIENT_TYPE_A;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_CLIENT_TYPE_B;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DESCRIPTION_A;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DESCRIPTION_B;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_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.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENT_TYPE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
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;
@@ -38,16 +43,17 @@
import seedu.address.logic.Messages;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
+import seedu.address.model.clienttype.ClientType;
import seedu.address.model.person.Address;
+import seedu.address.model.person.Description;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
import seedu.address.testutil.EditPersonDescriptorBuilder;
public class EditCommandParserTest {
- private static final String TAG_EMPTY = " " + PREFIX_TAG;
+ private static final String CLIENT_TYPE_EMPTY = " " + PREFIX_CLIENT_TYPE;
private static final String MESSAGE_INVALID_FORMAT =
String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE);
@@ -87,31 +93,41 @@ 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_CLIENT_TYPE_DESC,
+ ClientType.MESSAGE_CONSTRAINTS); // invalid client type
+ assertParseFailure(parser, "1" + INVALID_DESCRIPTION_DESC,
+ Description.MESSAGE_CONSTRAINTS); // invalid description
// 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);
+ // while parsing {@code PREFIX_CLIENT_TYPE} alone will reset
+ // the client types of the {@code Person} being edited,
+ // parsing it together with a valid client type results in error
+ assertParseFailure(parser, "1" + CLIENT_TYPE_DESC_A
+ + CLIENT_TYPE_DESC_B + CLIENT_TYPE_EMPTY, ClientType.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, "1" + CLIENT_TYPE_DESC_A
+ + CLIENT_TYPE_EMPTY + CLIENT_TYPE_DESC_B, ClientType.MESSAGE_CONSTRAINTS);
+ assertParseFailure(parser, "1" + CLIENT_TYPE_EMPTY
+ + CLIENT_TYPE_DESC_A + CLIENT_TYPE_DESC_B, ClientType.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,
+ assertParseFailure(parser, "1" + INVALID_NAME_DESC
+ + INVALID_EMAIL_DESC + VALID_ADDRESS_AMY + VALID_PHONE_AMY
+ + VALID_CLIENT_TYPE_A + VALID_DESCRIPTION_A,
Name.MESSAGE_CONSTRAINTS);
}
@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 + CLIENT_TYPE_DESC_B
+ + EMAIL_DESC_AMY + ADDRESS_DESC_AMY + NAME_DESC_AMY + CLIENT_TYPE_DESC_A + DESCRIPTION_DESC_A;
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();
+ .withClientTypes(VALID_CLIENT_TYPE_B, VALID_CLIENT_TYPE_A)
+ .withDescription(VALID_DESCRIPTION_A).build(); // reminders is not edited
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
@@ -156,9 +172,15 @@ public void parse_oneFieldSpecified_success() {
expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
- // tags
- userInput = targetIndex.getOneBased() + TAG_DESC_FRIEND;
- descriptor = new EditPersonDescriptorBuilder().withTags(VALID_TAG_FRIEND).build();
+ // client types
+ userInput = targetIndex.getOneBased() + CLIENT_TYPE_DESC_A;
+ descriptor = new EditPersonDescriptorBuilder().withClientTypes(VALID_CLIENT_TYPE_A).build();
+ expectedCommand = new EditCommand(targetIndex, descriptor);
+ assertParseSuccess(parser, userInput, expectedCommand);
+
+ //description
+ userInput = targetIndex.getOneBased() + DESCRIPTION_DESC_B;
+ descriptor = new EditPersonDescriptorBuilder().withDescription(VALID_DESCRIPTION_B).build();
expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
}
@@ -166,7 +188,7 @@ public void parse_oneFieldSpecified_success() {
@Test
public void parse_multipleRepeatedFields_failure() {
// More extensive testing of duplicate parameter detections is done in
- // AddCommandParserTest#parse_repeatedNonTagValue_failure()
+ // AddCommandParserTest#parse_repeatedNonClientTypeValue_failure()
// valid followed by invalid
Index targetIndex = INDEX_FIRST_PERSON;
@@ -181,8 +203,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;
+ + CLIENT_TYPE_DESC_A + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY + CLIENT_TYPE_DESC_A
+ + PHONE_DESC_BOB + ADDRESS_DESC_BOB + EMAIL_DESC_BOB + CLIENT_TYPE_DESC_B;
assertParseFailure(parser, userInput,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS));
@@ -196,13 +218,9 @@ public void parse_multipleRepeatedFields_failure() {
}
@Test
- public void parse_resetTags_success() {
+ public void parse_resetClientTypes_failure() {
Index targetIndex = INDEX_THIRD_PERSON;
- String userInput = targetIndex.getOneBased() + TAG_EMPTY;
-
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withTags().build();
- EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
-
- assertParseSuccess(parser, userInput, expectedCommand);
+ String userInput = targetIndex.getOneBased() + CLIENT_TYPE_EMPTY;
+ assertParseFailure(parser, userInput, Messages.MESSAGE_NO_CLIENT_TYPE);
}
}
diff --git a/src/test/java/seedu/address/logic/parser/FindAddressCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindAddressCommandParserTest.java
new file mode 100644
index 00000000000..85d7c87b20b
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FindAddressCommandParserTest.java
@@ -0,0 +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 org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.FindAddressCommand;
+import seedu.address.model.person.AddressContainsKeywordsPredicate;
+
+public class FindAddressCommandParserTest {
+
+ private FindAddressCommandParser parser = new FindAddressCommandParser();
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindAddressCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsFindAddressCommand() {
+ // no leading and trailing whitespaces
+ FindAddressCommand expectedFindAddressCommand =
+ new FindAddressCommand(new AddressContainsKeywordsPredicate("tampines blk"));
+ assertParseSuccess(parser, "tampines blk", expectedFindAddressCommand);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/FindClientTypeCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindClientTypeCommandParserTest.java
new file mode 100644
index 00000000000..ca1e35296d3
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FindClientTypeCommandParserTest.java
@@ -0,0 +1,47 @@
+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.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.FindClientTypeCommand;
+import seedu.address.model.person.ClientTypeContainsKeywordsPredicate;
+
+/**
+ * Contains unit tests for {@code FindClientTypeCommandParser}.
+ */
+public class FindClientTypeCommandParserTest {
+
+ private FindClientTypeCommandParser parser = new FindClientTypeCommandParser();
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindClientTypeCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsFindClientTypeCommand() {
+ // no leading and trailing whitespaces
+ FindClientTypeCommand expectedFindClientTypeCommand =
+ new FindClientTypeCommand(new ClientTypeContainsKeywordsPredicate(List.of("Investment")));
+ assertParseSuccess(parser, "Investment", expectedFindClientTypeCommand);
+ }
+
+ @Test
+ public void parse_invalidArgs_throwsParseException() {
+ // No inputs
+ assertParseFailure(parser, "",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindClientTypeCommand.MESSAGE_USAGE));
+
+
+ // Special Characters
+ assertParseFailure(parser, "$12",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindClientTypeCommand.MESSAGE_USAGE));
+ }
+
+}
diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
index d92e64d12f9..7148287dbf5 100644
--- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
@@ -5,11 +5,19 @@
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
import java.util.Arrays;
+import java.util.List;
import org.junit.jupiter.api.Test;
+import seedu.address.logic.commands.FindAddressCommand;
+import seedu.address.logic.commands.FindClientTypeCommand;
import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.FindNameCommand;
+import seedu.address.logic.commands.FindPhoneCommand;
+import seedu.address.model.person.AddressContainsKeywordsPredicate;
+import seedu.address.model.person.ClientTypeContainsKeywordsPredicate;
import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.person.PhoneBeginsWithKeywordPredicate;
public class FindCommandParserTest {
@@ -17,18 +25,155 @@ public class FindCommandParserTest {
@Test
public void parse_emptyArg_throwsParseException() {
- assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindCommand.MESSAGE_USAGE));
}
@Test
- public void parse_validArgs_returnsFindCommand() {
+ public void parse_validArgsName_returnsFindNameCommand() {
// no leading and trailing whitespaces
- FindCommand expectedFindCommand =
- new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
- assertParseSuccess(parser, "Alice Bob", expectedFindCommand);
+ FindNameCommand expectedFindNameCommand =
+ new FindNameCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
+ assertParseSuccess(parser, "n/Alice Bob", expectedFindNameCommand);
// multiple whitespaces between keywords
- assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFindCommand);
+ assertParseSuccess(parser, "n/ Alice Bob ", expectedFindNameCommand);
}
+ @Test
+ public void parse_invalidNameArgs_throwsParseException() {
+ assertParseFailure(parser, "n/", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindNameCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_emptyNameKeyword_throwsParseException() {
+ assertParseFailure(parser, "n/ ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindNameCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_multipleSpacesAfterPrefix_throwsParseException() {
+ assertParseFailure(parser, "n/ ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindNameCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_nameKeywordWithInvalidCharacters_throwsParseException() {
+ // Test with invalid characters like numbers
+ assertParseFailure(parser, "n/Alice123", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindNameCommand.MESSAGE_USAGE));
+
+ // Test with special characters not allowed (other than parenthesis)
+ assertParseFailure(parser, "n/Alice@", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindNameCommand.MESSAGE_USAGE));
+
+ // Test with mixed valid and invalid characters
+ assertParseFailure(parser, "n/Alice Bob$", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindNameCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validNameKeywordWithParenthesis_returnsFindNameCommand() {
+ // Test with valid name containing parentheses
+ FindNameCommand expectedFindNameCommand =
+ new FindNameCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob(NUS)")));
+ assertParseSuccess(parser, "n/Alice Bob(NUS)", expectedFindNameCommand);
+ }
+
+ @Test
+ public void parse_validArgsPhone_returnsFindPhoneCommand() {
+ // valid phone number
+ FindPhoneCommand expectedFindPhoneCommand =
+ new FindPhoneCommand(new PhoneBeginsWithKeywordPredicate("98765432"));
+ assertParseSuccess(parser, "p/98765432", expectedFindPhoneCommand);
+ }
+
+ @Test
+ public void parse_invalidPhoneArgs_throwsParseException() {
+ // missing phone number
+ assertParseFailure(parser, "p/", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindPhoneCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_nonNumericPhone_throwsParseException() {
+ // Test with non-numeric input
+ assertParseFailure(parser, "p/abcd", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindPhoneCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_phoneWithLeadingAndTrailingSpaces_returnsFindPhoneCommand() {
+ // Test with leading and trailing spaces around a valid phone number
+ FindPhoneCommand expectedFindPhoneCommand =
+ new FindPhoneCommand(new PhoneBeginsWithKeywordPredicate("98765432"));
+ assertParseSuccess(parser, "p/ 98765432 ", expectedFindPhoneCommand);
+ }
+
+ @Test
+ public void parse_phoneWithInvalidCharacters_throwsParseException() {
+ // Test with a phone number containing invalid characters
+ assertParseFailure(parser, "p/98765A432", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindPhoneCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgsAddress_returnsFindAddressCommand() {
+ // valid address
+ FindAddressCommand expectedFindAddressCommand =
+ new FindAddressCommand(new AddressContainsKeywordsPredicate("Serangoon Road"));
+ assertParseSuccess(parser, "a/Serangoon Road", expectedFindAddressCommand);
+
+ // address with multiple words
+ FindAddressCommand expectedMultiWordAddressCommand =
+ new FindAddressCommand(new AddressContainsKeywordsPredicate("123 Main Street"));
+ assertParseSuccess(parser, "a/123 Main Street", expectedMultiWordAddressCommand);
+ }
+
+ @Test
+ public void parse_invalidAddressArgs_throwsParseException() {
+ // missing address
+ assertParseFailure(parser, "a/", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindAddressCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgsClientType_returnsFindClientTypeCommand() {
+ // valid client type
+ FindClientTypeCommand expectedFindClientTypeCommand =
+ new FindClientTypeCommand(new ClientTypeContainsKeywordsPredicate(List.of("VIP")));
+ assertParseSuccess(parser, "c/VIP", expectedFindClientTypeCommand);
+ }
+
+ @Test
+ public void parse_invalidClientTypeArgs_throwsParseException() {
+ // missing client type
+ assertParseFailure(parser, "c/", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindClientTypeCommand.MESSAGE_USAGE));
+ }
+ @Test
+ public void parse_nonAlphanumericClientType_throwsParseException() {
+ // Test with a client type containing non-alphanumeric characters
+ assertParseFailure(parser, "c/@!$", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindClientTypeCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_clientTypeWithLeadingAndTrailingSpaces_returnsFindClientTypeCommand() {
+ // Test with leading and trailing spaces around a valid client type
+ FindClientTypeCommand expectedFindClientTypeCommand =
+ new FindClientTypeCommand(new ClientTypeContainsKeywordsPredicate(List.of("Corporate")));
+ assertParseSuccess(parser, "c/ Corporate ", expectedFindClientTypeCommand);
+ }
+
+ @Test
+ public void parse_clientTypeWithInvalidCharacters_throwsParseException() {
+ // Test with a client type containing invalid characters
+ assertParseFailure(parser, "c/Corporate@", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindClientTypeCommand.MESSAGE_USAGE));
+ }
+ @Test
+ public void parse_invalidPrefix_throwsParseException() {
+ // invalid prefix
+ assertParseFailure(parser, "e/email@example.com", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindCommand.MESSAGE_USAGE));
+ }
}
diff --git a/src/test/java/seedu/address/logic/parser/FindNameCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindNameCommandParserTest.java
new file mode 100644
index 00000000000..6c7d9b0a74d
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FindNameCommandParserTest.java
@@ -0,0 +1,64 @@
+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 org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.FindNameCommand;
+import seedu.address.model.person.NameContainsKeywordsPredicate;
+
+public class FindNameCommandParserTest {
+
+ private FindNameCommandParser parser = new FindNameCommandParser();
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindNameCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsFindCommand() {
+ // no leading and trailing whitespaces
+ FindNameCommand expectedFindCommand =
+ new FindNameCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
+ assertParseSuccess(parser, "Alice Bob", expectedFindCommand);
+
+ // multiple whitespaces between keywords
+ assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFindCommand);
+ }
+
+ @Test
+ public void parse_validArgsWithParenthesis_returnsFindCommand() {
+ // no leading and trailing whitespaces
+ FindNameCommand expectedFindCommand =
+ new FindNameCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob(NUS)")));
+ assertParseSuccess(parser, "Alice Bob(NUS)", expectedFindCommand);
+
+ // multiple whitespaces between keywords
+ assertParseSuccess(parser, " \n Alice \n \t Bob(NUS) \t", expectedFindCommand);
+ }
+
+ @Test
+ public void parse_nameWithInvalidCharacters_throwsParseException() {
+ // Test with invalid characters (e.g., numbers)
+ assertParseFailure(parser, "n/Alice123", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindNameCommand.MESSAGE_USAGE));
+
+ // Test with invalid characters (e.g., special characters)
+ assertParseFailure(parser, "n/Alice@Bob", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindNameCommand.MESSAGE_USAGE));
+
+ // Test with invalid characters (e.g., punctuation)
+ assertParseFailure(parser, "n/Alice!Bob", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindNameCommand.MESSAGE_USAGE));
+
+ // Test with mixed valid and invalid characters
+ assertParseFailure(parser, "n/Alice(Bob)@", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindNameCommand.MESSAGE_USAGE));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/FindPhoneCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindPhoneCommandParserTest.java
new file mode 100644
index 00000000000..811f09e644f
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/FindPhoneCommandParserTest.java
@@ -0,0 +1,47 @@
+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.FindPhoneCommand;
+import seedu.address.model.person.PhoneBeginsWithKeywordPredicate;
+
+public class FindPhoneCommandParserTest {
+
+ private FindPhoneCommandParser parser = new FindPhoneCommandParser();
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindPhoneCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsFindCommand() {
+ // no leading and trailing whitespaces
+ FindPhoneCommand expectedFindCommand =
+ new FindPhoneCommand(new PhoneBeginsWithKeywordPredicate("9876"));
+ assertParseSuccess(parser, "9876", expectedFindCommand);
+ }
+
+ @Test
+ public void parse_invalidArgs_throwsParseException() {
+ // multiple inputs
+ assertParseFailure(parser, "9876 9678",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindPhoneCommand.MESSAGE_USAGE));
+
+
+ // not number
+ assertParseFailure(parser, "string",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindPhoneCommand.MESSAGE_USAGE));
+
+
+ // non-number in betweennumber
+ assertParseFailure(parser, "987n9678",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindPhoneCommand.MESSAGE_USAGE));
+ }
+
+}
diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
index 4256788b1a7..751764fec16 100644
--- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
+++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
@@ -14,25 +14,34 @@
import org.junit.jupiter.api.Test;
import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.clienttype.ClientType;
import seedu.address.model.person.Address;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
public class ParserUtilTest {
private static final String INVALID_NAME = "R@chel";
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_CLIENT_TYPE = "#A";
+ private static final String INVALID_DESC = "apple banana orange mango grape lemon peach pear strawberry blueberry "
+ + "raspberry watermelon pineapple kiwi cherry lime grapefruit apricot plum coconut "
+ + "fig date nectarine cantaloupe guava papaya pomegranate cranberry tangerine blackberry currant "
+ + "dragonfruit lychee persimmon quince starfruit avocado passionfruit gooseberry mulberry "
+ + "elderberry boysenberry kumquat jujube "
+ + "yuzu ackee rambutan loquat carambola jabuticaba sapodilla medlar feijoa pawpaw salak "
+ + "tamarillo lucuma BLAH BLAH BLAH BLAH BLAH BLAH BLAH";
+
private static final String VALID_NAME = "Rachel Walker";
- private static final String VALID_PHONE = "123456";
+ private static final String VALID_PHONE = "12345678";
private static final String VALID_ADDRESS = "123 Main Street #0505";
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_CLIENT_TYPE_1 = "A";
+ private static final String VALID_CLIENT_TYPE_2 = "B";
+ private static final String VALID_DESC = "A type";
private static final String WHITESPACE = " \t\r\n";
@@ -44,7 +53,7 @@ public void parseIndex_invalidInput_throwsParseException() {
@Test
public void parseIndex_outOfRangeInput_throwsParseException() {
assertThrows(ParseException.class, MESSAGE_INVALID_INDEX, ()
- -> ParserUtil.parseIndex(Long.toString(Integer.MAX_VALUE + 1)));
+ -> ParserUtil.parseIndex(Long.toString(Integer.MAX_VALUE + 1)));
}
@Test
@@ -149,48 +158,63 @@ public void parseEmail_validValueWithWhitespace_returnsTrimmedEmail() throws Exc
}
@Test
- public void parseTag_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> ParserUtil.parseTag(null));
+ public void parseClientType_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> ParserUtil.parseClientType(null));
+ }
+
+ @Test
+ public void parseClientType_invalidValue_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parseClientType(INVALID_CLIENT_TYPE));
}
@Test
- public void parseTag_invalidValue_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parseTag(INVALID_TAG));
+ public void parseClientType_validValueWithoutWhitespace_returnsClientType() throws Exception {
+ ClientType expectedClientType = new ClientType(VALID_CLIENT_TYPE_1);
+ assertEquals(expectedClientType, ParserUtil.parseClientType(VALID_CLIENT_TYPE_1));
}
@Test
- public void parseTag_validValueWithoutWhitespace_returnsTag() throws Exception {
- Tag expectedTag = new Tag(VALID_TAG_1);
- assertEquals(expectedTag, ParserUtil.parseTag(VALID_TAG_1));
+ public void parseClientType_validValueWithWhitespace_returnsTrimmedClientType() throws Exception {
+ String clientTypeWithWhitespace = WHITESPACE + VALID_CLIENT_TYPE_1 + WHITESPACE;
+ ClientType expectedClientType = new ClientType(VALID_CLIENT_TYPE_1);
+ assertEquals(expectedClientType, ParserUtil.parseClientType(clientTypeWithWhitespace));
}
@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 parseClientTypes_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> ParserUtil.parseClientTypes(null));
}
@Test
- public void parseTags_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> ParserUtil.parseTags(null));
+ public void parseClientTypes_collectionWithInvalidClientTypes_throwsParseException() {
+ assertThrows(ParseException.class, () ->
+ ParserUtil.parseClientTypes(Arrays.asList(VALID_CLIENT_TYPE_1,
+ INVALID_CLIENT_TYPE)));
}
@Test
- public void parseTags_collectionWithInvalidTags_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, INVALID_TAG)));
+ public void parseClientTypes_emptyCollection_returnsEmptySet() throws Exception {
+ assertTrue(ParserUtil.parseClientTypes(Collections.emptyList()).isEmpty());
}
@Test
- public void parseTags_emptyCollection_returnsEmptySet() throws Exception {
- assertTrue(ParserUtil.parseTags(Collections.emptyList()).isEmpty());
+ public void parseClientTypes_collectionWithValidClientTypes_returnsClientTypeSet() throws Exception {
+ Set actualClientTypeSet = ParserUtil.parseClientTypes(Arrays.asList(VALID_CLIENT_TYPE_1,
+ VALID_CLIENT_TYPE_2));
+ Set expectedClientTypeSet = new HashSet(Arrays
+ .asList(new ClientType(VALID_CLIENT_TYPE_1), new ClientType(VALID_CLIENT_TYPE_2)));
+
+ assertEquals(expectedClientTypeSet, actualClientTypeSet);
}
@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)));
+ public void parseDescription_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> ParserUtil.parseDescription((String) null));
+ }
- assertEquals(expectedTagSet, actualTagSet);
+ @Test
+ public void parseDescription_invalidValue_throwsParseException() {
+ assertThrows(ParseException.class, () -> ParserUtil.parseDescription(INVALID_DESC));
}
+
}
diff --git a/src/test/java/seedu/address/logic/parser/ViewCommandParserTest.java b/src/test/java/seedu/address/logic/parser/ViewCommandParserTest.java
new file mode 100644
index 00000000000..749c71fa157
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/ViewCommandParserTest.java
@@ -0,0 +1,81 @@
+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 org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.ViewCommand;
+import seedu.address.model.person.NameContainsKeywordsPredicate;
+
+public class ViewCommandParserTest {
+
+ private ViewCommandParser parser = new ViewCommandParser();
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ ViewCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgs_returnsViewCommand() {
+ // no leading and trailing whitespaces
+ ViewCommand expectedFindCommand =
+ new ViewCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
+ assertParseSuccess(parser, "Alice Bob", expectedFindCommand);
+
+ // multiple whitespaces between keywords
+ assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFindCommand);
+ }
+
+ @Test
+ public void parse_validArgsWithParenthesis_returnsViewCommand() {
+ // no leading and trailing whitespaces
+ ViewCommand expectedFindCommand =
+ new ViewCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob(NUS)")));
+ assertParseSuccess(parser, "Alice Bob(NUS)", expectedFindCommand);
+
+ // multiple whitespaces between keywords
+ assertParseSuccess(parser, " \n Alice \n \t Bob(NUS) \t", expectedFindCommand);
+ }
+
+
+ @Test
+ public void parse_invalidArgsWithSpecialCharacters_throwsParseException() {
+ // Special characters
+ assertParseFailure(parser, "Alice@Bob", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ ViewCommand.MESSAGE_USAGE));
+
+ // Commas
+ assertParseFailure(parser, "Alice, Bob, Charlie", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ ViewCommand.MESSAGE_USAGE));
+
+ // Keywords with hyphens
+ assertParseFailure(parser, "John-Paul Mary-Anne", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ ViewCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_invalidArgsWithNumbers_throwsParseException() {
+ assertParseFailure(parser, "696969", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ ViewCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_invalidArgsWithNumbersAndLetters_throwsParseException() {
+ assertParseFailure(parser, "Alex123 Tan", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ ViewCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_validArgsWithMixedCaseKeywords_returnsViewCommand() {
+ // Mixed case keywords
+ ViewCommand expectedFindCommand =
+ new ViewCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "BOB", "ChArlie")));
+ assertParseSuccess(parser, "Alice BOB ChArlie", expectedFindCommand);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/reminder/AddReminderCommandParserTest.java b/src/test/java/seedu/address/logic/parser/reminder/AddReminderCommandParserTest.java
new file mode 100644
index 00000000000..ab84eb00f89
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/reminder/AddReminderCommandParserTest.java
@@ -0,0 +1,210 @@
+package seedu.address.logic.parser.reminder;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.time.LocalDateTime;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.reminder.AddReminderCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.reminder.Reminder;
+import seedu.address.model.reminder.ReminderDescription;
+
+
+public class AddReminderCommandParserTest {
+
+ private final AddReminderCommandParser parser = new AddReminderCommandParser();
+ @Test
+ public void parse_missingName_throwsParseException() {
+ String userInput = "dt/2021-12-31 23:59 d/New Year's Eve";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_missingDateTime_throwsParseException() {
+ String userInput = "n/John Doe d/New Year's Eve";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_missingDescription_throwsParseException() {
+ String userInput = "n/John Doe dt/2021-12-31 23:59";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_extraArguments_throwsParseException() {
+ String userInput = "n/John Doe dt/2021-12-31 23:59 d/New Year's Eve extraArg";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_invalidDateTimeFormat_throwsParseException() {
+ String userInput = "n/John Doe dt/2021-12-31 25:00 d/New Year's Eve";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+ @Test
+ public void parse_invalidDescriptionFormat_throwsParseException() {
+ String userInput = "n/John Doe dt/2021-12-31 23:59 d/"; // Empty description
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_invalidNameFormat_throwsParseException() {
+ String userInput = "n/ dt/2021-12-31 23:59 d/New Year's Eve"; // Empty name
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_invalidMonth_throwsParseException() {
+ String userInput = "n/John Doe dt/2021-13-31 23:59 d/New Year's Eve"; // Invalid month
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_duplicatePrefixes_throwsParseException() {
+ String userInput = "n/John Doe n/Jane Doe dt/2021-12-31 23:59 d/New Year's Eve"; // Duplicate name prefix
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_emptyInput_throwsParseException() {
+ String userInput = ""; // Empty input
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_onlyPrefixes_throwsParseException() {
+ String userInput = "n/ d/ dt/"; // All prefixes are present, but values are empty
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_success_withLeadingAndTrailingSpaces() throws ParseException {
+ String userInput = " n/John Doe dt/2021-12-31 23:59 d/New Year's Eve ";
+ AddReminderCommand command = parser.parse(userInput);
+
+ Reminder expectedReminder = new Reminder("John Doe",
+ LocalDateTime.of(2021, 12, 31, 23, 59),
+ new ReminderDescription("New Year's Eve"));
+ AddReminderCommand expectedCommand = new AddReminderCommand(expectedReminder);
+
+ assertEquals(expectedCommand, command);
+ }
+
+ @Test
+ public void parse_invalidCharactersInName_throwsParseException() {
+ String userInput = "n/John@Doe dt/2021-12-31 23:59 d/New Year's Eve"; // Invalid character in name
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_validInput_success() throws ParseException {
+ String userInput = " n/John Doe dt/2021-12-31 23:59 d/New Year's Eve";
+ AddReminderCommand command = parser.parse(userInput);
+
+ Reminder expectedReminder = new Reminder("John Doe",
+ LocalDateTime.of(2021, 12, 31, 23, 59),
+ new ReminderDescription("New Year's Eve"));
+ AddReminderCommand expectedCommand = new AddReminderCommand(expectedReminder);
+
+ assertEquals(expectedCommand, command);
+ }
+ @Test
+ public void parse_multipleSpacesBetweenArguments_success() throws ParseException {
+ String userInput = " n/John Doe dt/2021-12-31 23:59 d/New Year's Eve";
+ AddReminderCommand command = parser.parse(userInput);
+
+ Reminder expectedReminder = new Reminder("John Doe",
+ LocalDateTime.of(2021, 12, 31, 23, 59),
+ new ReminderDescription("New Year's Eve"));
+ AddReminderCommand expectedCommand = new AddReminderCommand(expectedReminder);
+ assertEquals(expectedCommand, command);
+ }
+
+ @Test
+ public void parse_validInput_withSpecialCharactersInDescription() throws ParseException {
+ String userInput = " n/John Doe dt/2021-12-31 23:59 d/New Year's Eve Party!";
+ AddReminderCommand command = parser.parse(userInput);
+ Reminder expectedReminder = new Reminder("John Doe",
+ LocalDateTime.of(2021, 12, 31, 23, 59),
+ new ReminderDescription("New Year's Eve Party!"));
+ AddReminderCommand expectedCommand = new AddReminderCommand(expectedReminder);
+ assertEquals(expectedCommand, command);
+ }
+ @Test
+ public void parse_dateTimeInPast_throwsParseException() {
+ String userInput = "n/John Doe dt/2000-01-01 12:00 d/Past Event";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_nameWithSpacesOnly_throwsParseException() {
+ String userInput = "n/ dt/2021-12-31 23:59 d/Description";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_descriptionWithSpacesOnly_throwsParseException() {
+ String userInput = "n/John Doe dt/2021-12-31 23:59 d/ ";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_trailingSpecialCharacterInName_throwsParseException() {
+ String userInput = "n/John Doe! dt/2021-12-31 23:59 d/Description";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_untrimmedName_success() throws ParseException {
+ String userInput = " n/ John Doe dt/2021-12-31 23:59 d/Description";
+ AddReminderCommand command = parser.parse(userInput);
+
+ Reminder expectedReminder = new Reminder("John Doe",
+ LocalDateTime.of(2021, 12, 31, 23, 59),
+ new ReminderDescription("Description"));
+ AddReminderCommand expectedCommand = new AddReminderCommand(expectedReminder);
+ assertEquals(expectedCommand, command);
+ }
+
+ @Test
+ public void parse_invalidDateWithoutTime_throwsParseException() {
+ String userInput = "n/John Doe dt/2021-12-31 d/Event";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_validInput_withEmptyPreamble() throws ParseException {
+ String userInput = " n/John Doe dt/2021-12-31 23:59 d/Valid Event";
+ AddReminderCommand command = parser.parse(userInput);
+
+ Reminder expectedReminder = new Reminder("John Doe",
+ LocalDateTime.of(2021, 12, 31, 23, 59),
+ new ReminderDescription("Valid Event"));
+ AddReminderCommand expectedCommand = new AddReminderCommand(expectedReminder);
+
+ assertEquals(expectedCommand, command);
+ }
+
+ @Test
+ public void parse_prefixesWithEmptyValuesAndExtraSpaces_throwsParseException() {
+ String userInput = "n/ dt/ d/ ";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_emptyDateTimeValue_throwsParseException() {
+ String userInput = "n/John Doe dt/ d/Description";
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+ @Test
+ public void parse_invalidDateFormat_throwsParseException() {
+ String userInput = "n/John Doe dt/31-12-2021 23:59 d/Event"; // Incorrect date format
+ assertThrows(ParseException.class, () -> parser.parse(userInput));
+ }
+
+}
diff --git a/src/test/java/seedu/address/logic/parser/reminder/DeleteReminderCommandParserTest.java b/src/test/java/seedu/address/logic/parser/reminder/DeleteReminderCommandParserTest.java
new file mode 100644
index 00000000000..13f79efde6a
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/reminder/DeleteReminderCommandParserTest.java
@@ -0,0 +1,26 @@
+package seedu.address.logic.parser.reminder;
+
+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 static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.reminder.DeleteReminderCommand;
+
+
+public class DeleteReminderCommandParserTest {
+ private DeleteReminderCommandParser parser = new DeleteReminderCommandParser();
+
+ @Test
+ public void parse_validArgs_returnsDeleteReminderCommand() {
+ assertParseSuccess(parser, "1", new DeleteReminderCommand(INDEX_FIRST_PERSON));
+ }
+
+ @Test
+ public void parse_invalidArgs_throwsParseException() {
+ assertParseFailure(parser, "", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteReminderCommand.MESSAGE_USAGE));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/reminder/EditReminderCommandParserTest.java b/src/test/java/seedu/address/logic/parser/reminder/EditReminderCommandParserTest.java
new file mode 100644
index 00000000000..228eed9f4d9
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/reminder/EditReminderCommandParserTest.java
@@ -0,0 +1,57 @@
+package seedu.address.logic.parser.reminder;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_TIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.reminder.EditReminderCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+public class EditReminderCommandParserTest {
+ private EditReminderCommandParser parser;
+
+ @BeforeEach
+ public void setUp() {
+ parser = new EditReminderCommandParser();
+ }
+
+ @Test
+ public void parse_noFieldsSpecified_throwsParseException() {
+ String userInput = "1"; // Only index provided
+ assertThrows(ParseException.class, () -> parser.parse(userInput),
+ EditReminderCommand.MESSAGE_REMINDER_NOT_EDITED);
+ }
+
+ @Test
+ public void parse_invalidIndex_throwsParseException() {
+ String userInput = "invalidIndex " + PREFIX_DATE_TIME + "2022-01-01 00:00";
+ assertThrows(ParseException.class, () -> parser.parse(userInput),
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditReminderCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_duplicateFields_throwsParseException() {
+ String userInput = "1 " + PREFIX_DATE_TIME + "2022-01-01 00:00 "
+ + PREFIX_DATE_TIME + "2022-02-01 00:00"; // Duplicate dateTime prefix
+ assertThrows(ParseException.class, () -> parser.parse(userInput),
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditReminderCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_invalidDateTime_throwsParseException() {
+ String userInput = "1 " + PREFIX_DATE_TIME + "invalidDateTime";
+ assertThrows(ParseException.class, () -> parser.parse(userInput),
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditReminderCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_invalidDescription_throwsParseException() {
+ String userInput = "1 " + PREFIX_DESCRIPTION + "";
+ assertThrows(ParseException.class, () -> parser.parse(userInput),
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditReminderCommand.MESSAGE_USAGE));
+ }
+}
diff --git a/src/test/java/seedu/address/model/AddressBookTest.java b/src/test/java/seedu/address/model/AddressBookTest.java
deleted file mode 100644
index 68c8c5ba4d5..00000000000
--- a/src/test/java/seedu/address/model/AddressBookTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package seedu.address.model;
-
-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.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.testutil.PersonBuilder;
-
-public class AddressBookTest {
-
- private final AddressBook addressBook = new AddressBook();
-
- @Test
- public void constructor() {
- assertEquals(Collections.emptyList(), addressBook.getPersonList());
- }
-
- @Test
- public void resetData_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> addressBook.resetData(null));
- }
-
- @Test
- public void resetData_withValidReadOnlyAddressBook_replacesData() {
- AddressBook newData = getTypicalAddressBook();
- addressBook.resetData(newData);
- assertEquals(newData, addressBook);
- }
-
- @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)
- .build();
- List newPersons = Arrays.asList(ALICE, editedAlice);
- AddressBookStub newData = new AddressBookStub(newPersons);
-
- assertThrows(DuplicatePersonException.class, () -> addressBook.resetData(newData));
- }
-
- @Test
- public void hasPerson_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> addressBook.hasPerson(null));
- }
-
- @Test
- public void hasPerson_personNotInAddressBook_returnsFalse() {
- assertFalse(addressBook.hasPerson(ALICE));
- }
-
- @Test
- public void hasPerson_personInAddressBook_returnsTrue() {
- addressBook.addPerson(ALICE);
- assertTrue(addressBook.hasPerson(ALICE));
- }
-
- @Test
- public void hasPerson_personWithSameIdentityFieldsInAddressBook_returnsTrue() {
- addressBook.addPerson(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
- .build();
- assertTrue(addressBook.hasPerson(editedAlice));
- }
-
- @Test
- public void getPersonList_modifyList_throwsUnsupportedOperationException() {
- assertThrows(UnsupportedOperationException.class, () -> addressBook.getPersonList().remove(0));
- }
-
- @Test
- public void toStringMethod() {
- String expected = AddressBook.class.getCanonicalName() + "{persons=" + addressBook.getPersonList() + "}";
- assertEquals(expected, addressBook.toString());
- }
-
- /**
- * A stub ReadOnlyAddressBook whose persons list can violate interface constraints.
- */
- private static class AddressBookStub implements ReadOnlyAddressBook {
- private final ObservableList persons = FXCollections.observableArrayList();
-
- AddressBookStub(Collection persons) {
- this.persons.setAll(persons);
- }
-
- @Override
- public ObservableList