Skip to content

Commit

Permalink
Merge pull request nus-cs2103-AY2425S1#58 from 1st2GetThisName/branch…
Browse files Browse the repository at this point in the history
…_add_vip

Add partial VIP implementation
  • Loading branch information
muller317 authored Oct 17, 2024
2 parents abe2bd0 + 680df86 commit 89cacb1
Show file tree
Hide file tree
Showing 14 changed files with 441 additions and 13 deletions.
16 changes: 16 additions & 0 deletions docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@ If your changes to the data file makes its format invalid, AddressBook will disc
Furthermore, certain edits can cause the AddressBook to behave in unexpected ways (e.g., if a value entered is outside the acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly.
</box>

### Marking whether a person is a VIP : `vip`

Marks the specified person from the address book as a VIP or removes said label.

Format: `vip INDEX IS_VIP`

* Affects the person at the specified `INDEX`.
* The index refers to the index number shown in the displayed person list.
* The index **must be a positive integer** 1, 2, 3, …​
* IS_VIP should either be `true` or `false`, corresponding to whether you intend to mark the target as a VIP or remove such a mark.

Examples:
* `list` followed by `vip 2 true` marks the 2nd person in the address book as a VIP.
* `find Betsy` followed by `vip 1 false` removes VIP status from the 1st person in the results of the `find` command.

### Archiving data files `[coming in v2.0]`

_Details coming soon ..._
Expand Down Expand Up @@ -202,4 +217,5 @@ Action | Format, Examples
**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…​`<br> e.g.,`edit 2 n/James Lee e/[email protected]`
**Find** | `find KEYWORD [MORE_KEYWORDS]`<br> e.g., `find James Jake`
**List** | `list`
**Vip** | `vip INDEX IS_VIP`<br> e.g., `vip 3 true`
**Help** | `help`
3 changes: 2 additions & 1 deletion src/main/java/seedu/address/logic/commands/EditCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,9 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript
Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
Comment updatedComment = editPersonDescriptor.getComment().orElse(personToEdit.getComment());
Set<Tag> updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
boolean isVip = personToEdit.isVip();

return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedComment, updatedTags);
return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedComment, updatedTags, isVip);
}

@Override
Expand Down
98 changes: 98 additions & 0 deletions src/main/java/seedu/address/logic/commands/MarkVipCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import java.util.List;
import java.util.Set;

import seedu.address.commons.core.index.Index;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.person.Address;
import seedu.address.model.person.Comment;
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;

/**
* Marks a person as a VIP or revokes that title.
*/
public class MarkVipCommand extends Command {

public static final String COMMAND_WORD = "vip";

public static final String MESSAGE_USAGE = COMMAND_WORD
+ ": Marks or unmarks the person identified by the index "
+ "number used in the displayed person list as a VIP.\n"
+ "Parameters: INDEX (must be a positive integer) IS_VIP (must be \"true\" or \"false\")\n"
+ "Example: " + COMMAND_WORD + " 1 true";

public static final String MESSAGE_VIP_PERSON_SUCCESS = "Person marked as a VIP: %1$s";
public static final String MESSAGE_UNVIP_PERSON_SUCCESS = "VIP status removed from person: %1$s";
public static final String MESSAGE_VIP_PERSON_OBSOLETE = "Person already a VIP: %1$s";
public static final String MESSAGE_UNVIP_PERSON_OBSOLETE = "Person not a VIP: %1$s";
private final String messageSuccess;
private final String messageObsolete;

private final Index targetIndex;
private final boolean newState;

/**
* Creates a MarkVipCommand to mark the specified {@code Person} as a VIP
* @param targetIndex the index of the Person in the list
* @param newState whether the Person should be labelled as a VIP when the operation is complete
*/
public MarkVipCommand(Index targetIndex, boolean newState) {
this.targetIndex = targetIndex;
this.newState = newState;
if (newState) {
messageSuccess = MESSAGE_VIP_PERSON_SUCCESS;
messageObsolete = MESSAGE_VIP_PERSON_OBSOLETE;
} else {
messageSuccess = MESSAGE_UNVIP_PERSON_SUCCESS;
messageObsolete = MESSAGE_UNVIP_PERSON_OBSOLETE;
}
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List<Person> lastShownList = model.getFilteredPersonList();

if (targetIndex.getZeroBased() >= lastShownList.size()) {
throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
}

Person personToMark = lastShownList.get(targetIndex.getZeroBased());
if (personToMark.isVip() == newState) {
return new CommandResult(String.format(messageObsolete, Messages.format(personToMark)));
}
Name name = personToMark.getName();
Address address = personToMark.getAddress();
Email email = personToMark.getEmail();
Phone phone = personToMark.getPhone();
Comment comment = personToMark.getComment();
Set<Tag> tags = personToMark.getTags();
Person updatedPerson = new Person(name, phone, email, address, comment, tags, newState);
model.setPerson(personToMark, updatedPerson);
return new CommandResult(String.format(messageSuccess, Messages.format(personToMark)));
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof MarkVipCommand)) {
return false;
}

MarkVipCommand otherMarkVipCommand = (MarkVipCommand) other;
return targetIndex.equals(otherMarkVipCommand.targetIndex) && newState == otherMarkVipCommand.newState;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
import seedu.address.logic.commands.MarkVipCommand;
import seedu.address.logic.commands.SearchCommand;
import seedu.address.logic.parser.exceptions.ParseException;

Expand Down Expand Up @@ -78,6 +79,10 @@ public Command parseCommand(String userInput) throws ParseException {
case HelpCommand.COMMAND_WORD:
return new HelpCommand();


case MarkVipCommand.COMMAND_WORD:
return new MarkVipCommandParser().parse(arguments);

case CommentCommand.COMMAND_WORD:
return new CommentCommandParser().parse(arguments);

Expand Down
47 changes: 47 additions & 0 deletions src/main/java/seedu/address/logic/parser/MarkVipCommandParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package seedu.address.logic.parser;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.MarkVipCommand;
import seedu.address.logic.parser.exceptions.ParseException;

/**
* Parses input arguments and creates a new MarkVipCommand.
*/
public class MarkVipCommandParser implements Parser<MarkVipCommand> {

/**
* Parses the given {@code String} of arguments in the context of the MarkVipCommand
* and returns a MarkVipCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public MarkVipCommand parse(String args) throws ParseException {
requireNonNull(args);
String trimmedArgs = args.trim();

String[] splitArgs = trimmedArgs.split("\\s+");

if (splitArgs.length != 2) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkVipCommand.MESSAGE_USAGE));
}
Index index;
try {
index = ParserUtil.parseIndex(splitArgs[0]);
} catch (ParseException pe) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkVipCommand.MESSAGE_USAGE), pe);
}
switch (splitArgs[1]) {
case "true":
return new MarkVipCommand(index, true);
case "false":
return new MarkVipCommand(index, false);
default:
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkVipCommand.MESSAGE_USAGE));
}
}
}
21 changes: 18 additions & 3 deletions src/main/java/seedu/address/model/person/Person.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,28 @@ public class Person {
// Data fields
private final Address address;
private final Set<Tag> tags = new HashSet<>();
private final boolean isVip;
private final Comment comment;

/**
* Every field must be present and not null.
* Every field must be present and not null. The customer will start as a non-VIP.
*/
public Person(Name name, Phone phone, Email email, Address address, Comment comment, Set<Tag> tags) {
this(name, phone, email, address, comment, tags, false);
}

/**
* Every field must be present and not null.
*/
public Person(Name name, Phone phone, Email email, Address address, Comment comment, Set<Tag> tags, boolean isVip) {
requireAllNonNull(name, phone, email, address, tags);
this.name = name;
this.phone = phone;
this.email = email;
this.address = address;
this.comment = comment;
this.tags.addAll(tags);
this.isVip = isVip;
}

public Name getName() {
Expand Down Expand Up @@ -67,6 +76,10 @@ public Set<Tag> getTags() {
return Collections.unmodifiableSet(tags);
}

public boolean isVip() {
return isVip;
}

/**
* Returns true if both persons have the same name.
* This defines a weaker notion of equality between two persons.
Expand Down Expand Up @@ -100,13 +113,14 @@ public boolean equals(Object other) {
&& phone.equals(otherPerson.phone)
&& email.equals(otherPerson.email)
&& address.equals(otherPerson.address)
&& tags.equals(otherPerson.tags);
&& tags.equals(otherPerson.tags)
&& isVip == otherPerson.isVip;
}

@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, tags, isVip);
}

@Override
Expand All @@ -118,6 +132,7 @@ public String toString() {
.add("address", address)
.add("comment", comment)
.add("tags", tags)
.add("isVip", isVip)
.toString();
}

Expand Down
17 changes: 15 additions & 2 deletions src/main/java/seedu/address/storage/JsonAdaptedPerson.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ class JsonAdaptedPerson {
private final String address;
private final String comment;
private final List<JsonAdaptedTag> tags = new ArrayList<>();
private final boolean isVip;

/**
* Constructs a {@code JsonAdaptedPerson} with the given person details.
*/
@JsonCreator
public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
@JsonProperty("email") String email, @JsonProperty("address") String address,
@JsonProperty("comment") String comment, @JsonProperty("tags") List<JsonAdaptedTag> tags) {
@JsonProperty("comment") String comment, @JsonProperty("tags") List<JsonAdaptedTag> tags,
@JsonProperty("isVip") boolean isVip) {
this.name = name;
this.phone = phone;
this.email = email;
Expand All @@ -47,6 +49,15 @@ public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone
if (tags != null) {
this.tags.addAll(tags);
}
this.isVip = isVip;
}

/**
* Constructs a {@code JsonAdaptedPerson} with the given person details, treating isVip as false.
*/
public JsonAdaptedPerson(String name, String phone, String email, String address,
String comment, List<JsonAdaptedTag> tags) {
this(name, phone, email, address, comment, tags, false);
}

/**
Expand All @@ -61,6 +72,7 @@ public JsonAdaptedPerson(Person source) {
tags.addAll(source.getTags().stream()
.map(JsonAdaptedTag::new)
.collect(Collectors.toList()));
isVip = source.isVip();
}

/**
Expand Down Expand Up @@ -110,7 +122,8 @@ public Person toModelType() throws IllegalValueException {
final Address modelAddress = new Address(address);
final Comment modelComment = new Comment("");
final Set<Tag> modelTags = new HashSet<>(personTags);
return new Person(modelName, modelPhone, modelEmail, modelAddress, modelComment, modelTags);

return new Person(modelName, modelPhone, modelEmail, modelAddress, modelComment, modelTags, isVip);
}

}
3 changes: 3 additions & 0 deletions src/main/java/seedu/address/ui/PersonCard.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public class PersonCard extends UiPart<Region> {
@FXML
private Label email;
@FXML
private Label vip;
@FXML
private FlowPane tags;
@FXML
private Label comment;
Expand All @@ -57,6 +59,7 @@ public PersonCard(Person person, int displayedIndex) {
person.getTags().stream()
.sorted(Comparator.comparing(tag -> tag.tagName))
.forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
vip.setVisible(person.isVip());
comment.setText(person.getComment().fullComment);
}
}
18 changes: 14 additions & 4 deletions src/main/resources/view/PersonListCard.fxml
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,41 @@
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>

<HBox id="cardPane" fx:id="cardPane" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1">
<HBox id="cardPane" fx:id="cardPane" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1">
<GridPane HBox.hgrow="ALWAYS">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10" prefWidth="150" />
</columnConstraints>
<VBox alignment="CENTER_LEFT" minHeight="105" GridPane.columnIndex="0">
<padding>
<Insets top="5" right="5" bottom="5" left="15" />
<Insets bottom="5" left="15" right="5" top="5" />
</padding>
<HBox spacing="0.5" alignment="CENTER_LEFT">
<HBox alignment="CENTER_LEFT" spacing="0.5">
<Label fx:id="id" styleClass="cell_big_label">
<minWidth>
<!-- Ensures that the label text is never truncated -->
<Region fx:constant="USE_PREF_SIZE" />
</minWidth>
</Label>
<Label fx:id="name" text="\$first" styleClass="cell_big_label" />
<Label fx:id="name" styleClass="cell_big_label" text="\$first" />
</HBox>
<FlowPane fx:id="tags" />
<Label fx:id="phone" styleClass="cell_small_label" text="\$phone" />
<Label fx:id="address" styleClass="cell_small_label" text="\$address" />
<Label fx:id="email" styleClass="cell_small_label" text="\$email" />
<Label fx:id="vip" text="VIP">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
<Label fx:id="comment" styleClass="cell_small_label" text="\$comment" />
</VBox>
<rowConstraints>
<RowConstraints />
</rowConstraints>
</GridPane>
</HBox>
Loading

0 comments on commit 89cacb1

Please sign in to comment.