diff --git a/.gitignore b/.gitignore index 823d175eb670..60984fd175fe 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ lib/* *.log *.log.* *.csv -config.json +/config.json src/test/data/sandbox/ preferences.json .DS_Store @@ -18,3 +18,4 @@ classes/ /bin/ src/main/resources/docs/ out/ +Certs/ diff --git a/LICENSE b/LICENSE index 39b3478982c3..c1cc39d91d98 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ MIT License Copyright (c) 2016 Software Engineering Education - FOSS Resources -Permission is hereby granted, free of charge, to any person obtaining a copy +Permission is hereby granted, free of charge, to any volunteer obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell diff --git a/README.adoc b/README.adoc index 450054624f48..636f2fdf8972 100644 --- a/README.adoc +++ b/README.adoc @@ -1,11 +1,9 @@ -= Address Book (Level 4) += SocialCare ifdef::env-github,env-browser[:relfileprefix: docs/] -https://travis-ci.org/se-edu/addressbook-level4[image:https://travis-ci.org/se-edu/addressbook-level4.svg?branch=master[Build Status]] -https://ci.appveyor.com/project/damithc/addressbook-level4[image:https://ci.appveyor.com/api/projects/status/3boko2x2vr5cc3w2?svg=true[Build status]] -https://coveralls.io/github/se-edu/addressbook-level4?branch=master[image:https://coveralls.io/repos/github/se-edu/addressbook-level4/badge.svg?branch=master[Coverage Status]] -https://www.codacy.com/app/damith/addressbook-level4?utm_source=github.com&utm_medium=referral&utm_content=se-edu/addressbook-level4&utm_campaign=Badge_Grade[image:https://api.codacy.com/project/badge/Grade/fc0b7775cf7f4fdeaf08776f3d8e364a[Codacy Badge]] -https://gitter.im/se-edu/Lobby[image:https://badges.gitter.im/se-edu/Lobby.svg[Gitter chat]] +https://travis-ci.org/CS2103-AY1819S1-W16-2/main[image:https://travis-ci.org/CS2103-AY1819S1-W16-2/main.svg?branch=master[Build Status]] +https://ci.appveyor.com/project/Kratious/main[image:https://ci.appveyor.com/api/projects/status/suon744fyw9kqi3x?svg=true[Build status]] +https://coveralls.io/github/CS2103-AY1819S1-W16-2/main?branch=master[image:https://coveralls.io/repos/github/CS2103-AY1819S1-W16-2/main/badge.svg?branch=master[Coverage Status]] ifdef::env-github[] image::docs/images/Ui.png[width="600"] @@ -15,24 +13,27 @@ ifndef::env-github[] image::images/Ui.png[width="600"] endif::[] -* This is a desktop Address Book application. It has a GUI but most of the user interactions happen using a CLI (Command Line Interface). -* It is a Java sample application intended for students learning Software Engineering while using Java as the main programming language. -* It is *written in OOP fashion*. It provides a *reasonably well-written* code example that is *significantly bigger* (around 6 KLoC)than what students usually write in beginner-level SE modules. -* What's different from https://github.com/se-edu/addressbook-level3[level 3]: -** A more sophisticated GUI that includes a list panel and an in-built Browser. -** More test cases, including automated GUI testing. -** Support for _Build Automation_ using Gradle and for _Continuous Integration_ using Travis CI. +* SocialCare is a social welfare event and volunteer management system. It is a desktop application and has a GUI but most of the user interactions happen using a CLI (Command Line Interface). +* It is *written in OOP fashion*, and is morphed from the https://se-edu.github.io/docs/Team.html[se-edu] team's https://github.com/nus-cs2103-AY1819S1/addressbook-level4[Address Book - Level 4], which provides a *reasonably well-written* code example that is *significantly bigger* (around 6 KLoC) than what students usually write in beginner-level SE modules. +* This application is intended for social welfare organisations that want to better manage their volunteers & events, and export volunteer certificates. +* SocialCare allows users to: +** Manage contacts and events faster than a typical mouse/GUI driven app. +** Use tags to categorize events and volunteers. +** Manage additional volunteer data, such as number of service hours per volunteer. +** Export volunteer certificates detailing each volunteer's involvement in the organisation's events. + == Site Map * <> * <> -* <> * <> * <> == Acknowledgements +* This application is based on https://github.com/nus-cs2103-AY1819S1/addressbook-level4[Address Book - Level 4] developed by +the https://se-edu.github.io/docs/Team.html[se-edu] team. * Some parts of this sample application were inspired by the excellent http://code.makery.ch/library/javafx-8-tutorial/[Java FX tutorial] by _Marco Jakob_. * Libraries used: https://github.com/TestFX/TestFX[TextFX], https://bitbucket.org/controlsfx/controlsfx/[ControlsFX], https://github.com/FasterXML/jackson[Jackson], https://github.com/google/guava[Guava], https://github.com/junit-team/junit5[JUnit5] diff --git a/_reposense/config.json b/_reposense/config.json new file mode 100644 index 000000000000..75985d19e6af --- /dev/null +++ b/_reposense/config.json @@ -0,0 +1,30 @@ +{ + "authors": + [ + { + "githubId": "afiqlattif", + "displayName": "MUHAM...ATTIF", + "authorNames": ["afiqlattif", "Afiq Lattif"] + }, + { + "githubId": "Scrubbius", + "displayName": "NGOH ...N JUN", + "authorNames": ["Scrubbius"] + }, + { + "githubId": "Kratious", + "displayName": "SEM J...G HAN", + "authorNames": ["Kratious"] + }, + { + "githubId": "sharan8", + "displayName": "THANG...HARAN", + "authorNames": ["sharan8", "Sharan"] + }, + { + "githubId": "iMarbles", + "displayName": "YEO Y...MABEL", + "authorNames": ["iMarbles"] + } + ] +} diff --git a/build.gradle b/build.gradle index f8e614f8b49b..ba884c57b9fa 100644 --- a/build.gradle +++ b/build.gradle @@ -79,6 +79,8 @@ dependencies { testRuntimeOnly group: 'org.testfx', name: 'openjfx-monocle', version: 'jdk-9+181' testRuntimeOnly group:'org.junit.vintage', name:'junit-vintage-engine', version: jUnitVersion testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: jUnitVersion + + compile 'org.apache.pdfbox:pdfbox:2.0.2' } shadowJar { @@ -207,9 +209,8 @@ asciidoctor { idprefix: '', // for compatibility with GitHub preview idseparator: '-', 'site-root': "${sourceDir}", // must be the same as sourceDir, do not modify - 'site-name': 'AddressBook-Level4', - 'site-githuburl': 'https://github.com/se-edu/addressbook-level4', - 'site-seedu': true, // delete this line if your project is not a fork (not a SE-EDU project) + 'site-name': 'SocialCare', + 'site-githuburl': 'https://github.com/CS2103-AY1819S1-W16-2/main' ] options['template_dirs'].each { diff --git a/docs/AboutUs.adoc b/docs/AboutUs.adoc index e647ed1e715a..952d3970e30d 100644 --- a/docs/AboutUs.adoc +++ b/docs/AboutUs.adoc @@ -4,53 +4,49 @@ :imagesDir: images :stylesDir: stylesheets -AddressBook - Level 4 was developed by the https://se-edu.github.io/docs/Team.html[se-edu] team. + -_{The dummy content given below serves as a placeholder to be used by future forks of the project.}_ + -{empty} + -We are a team based in the http://www.comp.nus.edu.sg[School of Computing, National University of Singapore]. - == Project Team -=== John Doe -image::damithc.jpg[width="150", align="left"] -{empty}[http://www.comp.nus.edu.sg/~damithch[homepage]] [https://github.com/damithc[github]] [<>] +=== Afiq Lattif +image::afiqlattif.png[width="150", align="left"] +{empty}[https://github.com/afiqlattif[github]] [<>] -Role: Project Advisor +Role: Developer + +Responsibilities: Volunteer Management Feature ''' -=== John Roe -image::lejolly.jpg[width="150", align="left"] -{empty}[http://github.com/lejolly[github]] [<>] +=== Sem Jing Han +image::kratious.png[width="150", align="left"] +{empty}[http://github.com/kratious[github]] [<>] -Role: Team Lead + -Responsibilities: UI +Role: Developer + +Responsibilities: Event Management Feature ''' -=== Johnny Doe -image::yijinl.jpg[width="150", align="left"] -{empty}[http://github.com/yijinl[github]] [<>] +=== Amabel Yeo +image::imarbles.png[width="150", align="left"] +{empty}[https://github.com/iMarbles[github]] [<>] Role: Developer + -Responsibilities: Data +Responsibilities: Assignment of Volunteers Feature ''' -=== Johnny Roe -image::m133225.jpg[width="150", align="left"] -{empty}[http://github.com/m133225[github]] [<>] +=== Thangavel Sharan +image::sharan8.png[width="150", align="left"] +{empty}[https://github.com/sharan8[github]] [<>] Role: Developer + -Responsibilities: Dev Ops + Threading +Responsibilities: Certificate Export Feature ''' -=== Benson Meier +=== Ngoh Wen Jun image::yl_coder.jpg[width="150", align="left"] -{empty}[http://github.com/yl-coder[github]] [<>] +{empty}[https://github.com/Scrubbius[github]] [<>] Role: Developer + -Responsibilities: UI +Responsibilities: Data Management Feature ''' diff --git a/docs/DeveloperGuide.adoc b/docs/DeveloperGuide.adoc index 817ec81d7832..e49a77aa357a 100644 --- a/docs/DeveloperGuide.adoc +++ b/docs/DeveloperGuide.adoc @@ -1,4 +1,4 @@ -= AddressBook Level 4 - Developer Guide += SocialCare - Developer Guide :site-section: DeveloperGuide :toc: :toc-title: @@ -13,21 +13,49 @@ ifdef::env-github[] :warning-caption: :warning: :experimental: endif::[] -:repoURL: https://github.com/se-edu/addressbook-level4/tree/master +:repoURL: https://github.com/CS2103-AY1819S1-W16-2/main/blob/master/ -By: `Team SE-EDU`      Since: `Jun 2016`      Licence: `MIT` +By: `Team W16-2`      Since: `Sept 2018`      Licence: `MIT` -== Setting up +== Introduction + +Welcome to SocialCare's Developer Guide! + +=== What is SocialCare? + +SocialCare is a CLI-based event and volunteer management system designed for social welfare organisations. It enables the following: + +* Faster volunteer and event management (than a typical mouse/GUI driven app). +* Tagging to categorize volunteers and events. +* Managing additional volunteer data, such as number of service hours per volunteer. +* Viewing of volunteer and event statistics. + +=== Core team + +SocialCare was developed and is maintained by https://github.com/CS2103-AY1819S1-W16-2[Team W16-2]. Due credit goes to the https://se-edu.github.io/docs/Team.html[se-edu] team, whose application https://github.com/nus-cs2103-AY1819S1/addressbook-level4[Address Book - Level 4] was morphed into SocialCare. + +Feel free to <> to us regarding any enquiries or clarifications. + +=== Contributing + +SocialCare is an open source project, and thus contributions are always welcome. Let's get you on board! + +To get started, head on to <>. + +[[Setting-Up]] +== Setting Up +This section will describe the steps to successfully set up the project on your computer. === Prerequisites +Before setting up your project, you will need: -. *JDK `9`* or later +* *JDK `9`* or later. + [WARNING] JDK `10` on Windows will fail to run tests in <> due to a https://github.com/javafxports/openjdk-jfx/issues/66[JavaFX bug]. Windows developers are highly recommended to use JDK `9`. -. *IntelliJ* IDE +* *IntelliJ* IDE. + [NOTE] IntelliJ by default has Gradle and JavaFx plugins installed. + @@ -35,53 +63,51 @@ Do not disable them. If you have disabled them, go to `File` > `Settings` > `Plu === Setting up the project in your computer - -. Fork this repo, and clone the fork to your computer -. Open IntelliJ (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project dialog first) -. Set up the correct JDK version for Gradle -.. Click `Configure` > `Project Defaults` > `Project Structure` -.. Click `New...` and find the directory of the JDK -. Click `Import Project` -. Locate the `build.gradle` file and select it. Click `OK` -. Click `Open as Project` -. Click `OK` to accept the default settings +Here are the steps to set up the project in your computer: + +. link:https://github.com/CS2103-AY1819S1-W16-2/main[Fork] this repo, and clone the fork to your computer. +. Open IntelliJ (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project dialog first). +. Set up the correct JDK version for Gradle. +.. Click `Configure` > `Project Defaults` > `Project Structure`. +.. Click `New...` and find the directory of the JDK. +. Click `Import Project`. +. Locate the `build.gradle` file and select it. Click `OK`. +. Click `Open as Project`. +. Click `OK` to accept the default settings. . Open a console and run the command `gradlew processResources` (Mac/Linux: `./gradlew processResources`). It should finish with the `BUILD SUCCESSFUL` message. + This will generate all resources required by the application and tests. -. Open link:{repoURL}/src/main/java/seedu/address/storage/XmlAdaptedPerson.java[`XmlAdaptedPerson.java`] and link:{repoURL}/src/main/java/seedu/address/ui/MainWindow.java[`MainWindow.java`] and check for any code errors -.. Due to an ongoing https://youtrack.jetbrains.com/issue/IDEA-189060[issue] with some of the newer versions of IntelliJ, code errors may be detected even if the project can be built and run successfully -.. To resolve this, place your cursor over any of the code section highlighted in red. Press kbd:[ALT + ENTER], and select `Add '--add-modules=...' to module compiler options` for each error -. Repeat this for the test folder as well (e.g. check link:{repoURL}/src/test/java/seedu/address/commons/util/XmlUtilTest.java[`XmlUtilTest.java`] and link:{repoURL}/src/test/java/seedu/address/ui/HelpWindowTest.java[`HelpWindowTest.java`] for code errors, and if so, resolve it the same way) +. Open link:{repoURL}/src/main/java/seedu/address/storage/XmlAdaptedPerson.java[`XmlAdaptedPerson.java`] and link:{repoURL}/src/main/java/seedu/address/ui/MainWindow.java[`MainWindow.java`] and check for any code errors. ++ +[NOTE] +Due to an ongoing https://youtrack.jetbrains.com/issue/IDEA-189060[issue] with some of the newer versions of IntelliJ, code errors may be detected even if the project can be built and run successfully. +To resolve this, place your cursor over any of the code section highlighted in red. +Press kbd:[ALT + ENTER], and select `Add '--add-modules=...' to module compiler options` for each error. +. Repeat this for the test folder as well (e.g. check link:{repoURL}/src/test/java/seedu/address/commons/util/XmlUtilTest.java[`XmlUtilTest.java`] and link:{repoURL}/src/test/java/seedu/address/ui/HelpWindowTest.java[`HelpWindowTest.java`] for code errors, and if so, resolve it the same way). === Verifying the setup +To verify that you have successfully set up your project on your computer, you must: -. Run the `seedu.address.MainApp` and try a few commands -. <> to ensure they all pass. +* Run the `seedu.address.MainApp` and try a few commands. +* <> and ensure that they all pass. === Configurations to do before writing code +Before you can start writing some code for your project, you must first set up the configurations for your project. ==== Configuring the coding style -This project follows https://github.com/oss-generic/process/blob/master/docs/CodingStandards.adoc[oss-generic coding standards]. IntelliJ's default style is mostly compliant with ours but it uses a different import order from ours. To rectify, +This project follows https://github.com/oss-generic/process/blob/master/docs/CodingStandards.adoc[oss-generic coding standards]. IntelliJ's default style is mostly compliant with ours but it uses a different import order from ours. To rectify this issue, you must: -. Go to `File` > `Settings...` (Windows/Linux), or `IntelliJ IDEA` > `Preferences...` (macOS) -. Select `Editor` > `Code Style` > `Java` -. Click on the `Imports` tab to set the order +. Go to `File` > `Settings...` (Windows/Linux), or `IntelliJ IDEA` > `Preferences...` (macOS). +. Select `Editor` > `Code Style` > `Java`. +. Click on the `Imports` tab to set the order. -* For `Class count to use import with '\*'` and `Names count to use static import with '*'`: Set to `999` to prevent IntelliJ from contracting the import statements -* For `Import Layout`: The order is `import static all other imports`, `import java.\*`, `import javax.*`, `import org.\*`, `import com.*`, `import all other imports`. Add a `` between each `import` +. Set `Class count to use import with '\*'` and `Names count to use static import with '*'` to `999` to prevent IntelliJ from contracting the import statements. +. Set the order of `Import Layout` to `import static all other imports`, `import java.\*`, `import javax.*`, `import org.\*`, `import com.*`, `import all other imports` and add a `` between each `import`. ++ +[NOTE] Optionally, you can follow the <> document to configure Intellij to check style-compliance as you write code. -==== Updating documentation to match your fork - -After forking the repo, the documentation will still have the SE-EDU branding and refer to the `se-edu/addressbook-level4` repo. - -If you plan to develop this fork as a separate product (i.e. instead of contributing to `se-edu/addressbook-level4`), you should do the following: - -. Configure the <> in link:{repoURL}/build.gradle[`build.gradle`], such as the `site-name`, to suit your own project. - -. Replace the URL in the attribute `repoURL` in link:{repoURL}/docs/DeveloperGuide.adoc[`DeveloperGuide.adoc`] and link:{repoURL}/docs/UserGuide.adoc[`UserGuide.adoc`] with the URL of your fork. - ==== Setting up CI Set up Travis to perform Continuous Integration (CI) for your fork. See <> to learn how to set it up. @@ -94,57 +120,34 @@ Coverage reporting could be useful for a team repository that hosts the final ve Optionally, you can set up AppVeyor as a second CI (see <>). [NOTE] -Having both Travis and AppVeyor ensures your App works on both Unix-based platforms and Windows-based platforms (Travis is Unix-based and AppVeyor is Windows-based) +Having both Travis and AppVeyor ensures your App works on both Unix-based platforms and Windows-based platforms (Travis is Unix-based and AppVeyor is Windows-based). ==== Getting started with coding -When you are ready to start coding, +When you are ready to start coding, you should: -1. Get some sense of the overall design by reading <>. -2. Take a look at <>. +* Get some sense of the overall design by reading <>. +* Take a look at <>. == Design +This section will describe the design architecture and the various components of the system. [[Design-Architecture]] === Architecture -.Architecture Diagram -image::Architecture.png[width="600"] - -The *_Architecture Diagram_* given above explains the high-level design of the App. Given below is a quick overview of each component. +This section describes the design architecture used by the system. [TIP] The `.pptx` files used to create diagrams in this document can be found in the link:{repoURL}/docs/diagrams/[diagrams] folder. To update a diagram, modify the diagram in the pptx file, select the objects of the diagram, and choose `Save as picture`. -`Main` has only one class called link:{repoURL}/src/main/java/seedu/address/MainApp.java[`MainApp`]. It is responsible for, - -* At app launch: Initializes the components in the correct sequence, and connects them up with each other. -* At shut down: Shuts down the components and invokes cleanup method where necessary. - -<> represents a collection of classes used by multiple other components. Two of those classes play important roles at the architecture level. - -* `EventsCenter` : This class (written using https://github.com/google/guava/wiki/EventBusExplained[Google's Event Bus library]) is used by components to communicate with other components using events (i.e. a form of _Event Driven_ design) -* `LogsCenter` : Used by many classes to write log messages to the App's log file. - -The rest of the App consists of four components. - -* <>: The UI of the App. -* <>: The command executor. -* <>: Holds the data of the App in-memory. -* <>: Reads data from, and writes data to, the hard disk. - -Each of the four components +.Architecture diagram +image::Architecture.png[width="600"] -* Defines its _API_ in an `interface` with the same name as the Component. -* Exposes its functionality using a `{Component Name}Manager` class. +The *_Architecture Diagram_* given above explains the high-level design of the App. + -For example, the `Logic` component (see the class diagram given below) defines it's API in the `Logic.java` interface and exposes its functionality using the `LogicManager.java` class. +=== Events-driven nature of the design -.Class Diagram of the Logic Component -image::LogicClassDiagram.png[width="800"] - -[discrete] -==== Events-Driven nature of the design +SocialCare uses an event-driven architecture style. + The _Sequence Diagram_ below shows how the components interact for the scenario where the user issues the command `delete 1`. @@ -154,91 +157,144 @@ image::SDforDeletePerson.png[width="800"] [NOTE] Note how the `Model` simply raises a `AddressBookChangedEvent` when the Address Book data are changed, instead of asking the `Storage` to save the updates to the hard disk. -The diagram below shows how the `EventsCenter` reacts to that event, which eventually results in the updates being saved to the hard disk and the status bar of the UI being updated to reflect the 'Last Updated' time. +The figure below shows how the `EventsCenter` reacts to that event, which eventually results in the updates being saved to the hard disk and the status bar of the UI being updated to reflect the 'Last Updated' time. .Component interactions for `delete 1` command (part 2) image::SDforDeletePersonEventHandling.png[width="800"] [NOTE] -Note how the event is propagated through the `EventsCenter` to the `Storage` and `UI` without `Model` having to be coupled to either of them. This is an example of how this Event Driven approach helps us reduce direct coupling between components. +Note how the event is propagated through the `EventsCenter` to the `Storage` and `UI` without `Model` having to be coupled to either of them. This is an example of how an event-driven approach helps us to reduce direct coupling between components. + +=== Components -The sections below give more details of each component. +There are *6* main components: `Main`, `Commons`, `UI`, `Logic`, `Model`, and `Storage`. + +Given below is a brief overview of each component. + +<> is the starting point of the system, which encapsulates the other components. + +<> represents a collection of classes used by multiple components. + +<> contains the user interface classes used by the application. + +<> used to execute user commands. It is also known as the command executor. + +<> holds the data of the application in-memory. + +<> which allows reading and writing of data to the hard disk. + +For the `UI`, `Logic`, `Model` and `Storage` components they: + +* Define their _API_ in an `interface` with the same name as the Component. +* Expose their functionality using a `{Component Name}Manager` class. + +For example, the `Logic` component (see the figure given below) defines its API in the `Logic.java` interface and exposes its functionality using the `LogicManager.java` class. + +.Class diagram of the Logic component +image::LogicClassDiagram.png[width="800"] + +[[Design-Main]] +==== Main component + +`Main` has only one class called link:{repoURL}/src/main/java/seedu/address/MainApp.java[`MainApp`]. It is responsible for: + +* At app launch: Initializing the components in the correct sequence, and connecting them up with each other. +* At shut down: Shutting down the components and invoking cleanup methods where necessary. + +[[Design-Commons]] +==== Commons component + +`Commons` has classes used by multiple components. The classes are in the `seedu.addressbook.commons` package. + +Two of those classes play important roles at the architecture level. + +* `EventsCenter` : This class (written using https://github.com/google/guava/wiki/EventBusExplained[Google's Event Bus library]) is used by the different components to communicate with other components using events. (i.e. a form of _Event Driven_ design) +* `LogsCenter` : Used by the classes to write log messages to the App's log file. [[Design-Ui]] -=== UI component +==== UI component + +The `UI` component contains classes which are responsible for displaying the user interface of the system. The figure below shows the structure of the `UI` component. -.Structure of the UI Component +.Structure of the UI component image::UiClassDiagram.png[width="800"] *API* : link:{repoURL}/src/main/java/seedu/address/ui/Ui.java[`Ui.java`] -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter`, `BrowserPanel` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class. +The `UI` component consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter`, `BrowserPanel` etc. All these, including the `MainWindow`, inherits from the abstract `UiPart` class. -The `UI` component uses JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the link:{repoURL}/src/main/java/seedu/address/ui/MainWindow.java[`MainWindow`] is specified in link:{repoURL}/src/main/resources/view/MainWindow.fxml[`MainWindow.fxml`] +The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the link:{repoURL}/src/main/java/seedu/address/ui/MainWindow.java[`MainWindow`] is specified in link:{repoURL}/src/main/resources/view/MainWindow.fxml[`MainWindow.fxml`] -The `UI` component, +The `UI` component does the following: * Executes user commands using the `Logic` component. -* Binds itself to some data in the `Model` so that the UI can auto-update when data in the `Model` change. +* Binds itself to some data in the `Model` so that the UI can automatically update when data in the `Model` changes. * Responds to events raised from various parts of the App and updates the UI accordingly. [[Design-Logic]] -=== Logic component +==== Logic component + +The `Logic` component contains classes which are needed to execute user commands. The figure below shows the structure of the `Logic` component [[fig-LogicClassDiagram]] -.Structure of the Logic Component +.Structure of the Logic component image::LogicClassDiagram.png[width="800"] *API* : link:{repoURL}/src/main/java/seedu/address/logic/Logic.java[`Logic.java`] -. `Logic` uses the `AddressBookParser` class to parse the user command. -. This results in a `Command` object which is executed by the `LogicManager`. -. The command execution can affect the `Model` (e.g. adding a person) and/or raise events. -. The result of the command execution is encapsulated as a `CommandResult` object which is passed back to the `Ui`. +The flow for the `Logic` component is as follows: + +. `Logic` uses the `AddressBookParser` class to parse the user command. +. The `Command` object (which is automatically created in the previous step) is executed by the `LogicManager`. +. The executed `Command` affects the `Model` (e.g. adding a volunteer) and/or raise events. +. The result of the command execution from the previous step is encapsulated as a `CommandResult` object. +. The `CommandResult` object is passed back to the `UI` component. -Given below is the Sequence Diagram for interactions within the `Logic` component for the `execute("delete 1")` API call. +The figure below shows the Sequence Diagram for interactions within the `Logic` component for the `execute("delete 1")` API call. -.Interactions Inside the Logic Component for the `delete 1` Command +.Interactions inside the Logic component for the `delete 1` command image::DeletePersonSdForLogic.png[width="800"] + [[Design-Model]] -=== Model component +==== Model component + +The `Model` component contains classes which are responsible for managing the data of the application. The figure below shows the structure of the `Model` component. .Structure of the Model Component image::ModelClassDiagram.png[width="800"] *API* : link:{repoURL}/src/main/java/seedu/address/model/Model.java[`Model.java`] -The `Model`, +The `Model` component does the following: + +* Stores a `UserPref` object that represents the user's preferences. +* Stores the Address Book data. +* Exposes an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list changes. -* stores a `UserPref` object that represents the user's preferences. -* stores the Address Book data. -* exposes an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. -* does not depend on any of the other three components. +Note that the `Model` component does not depend on any of the other components. [NOTE] -As a more OOP model, we can store a `Tag` list in `Address Book`, which `Person` can reference. This would allow `Address Book` to only require one `Tag` object per unique `Tag`, instead of each `Person` needing their own `Tag` object. An example of how such a model may look like is given below. + - + -image:ModelClassBetterOopDiagram.png[width="800"] +As a more OOP model, we can store a `Tag` list in `SocialCare`, which `Volunteer` can reference. This would allow `SocialCare` to only require one `Tag` object per unique `Tag`, instead of each `Volunteer` needing their own `Tag` object. + +An example of how such a model may look like is given in the figure below. + + +.Example of a more OOP Model +image::ModelClassBetterOopDiagram.png[width="800"] [[Design-Storage]] -=== Storage component +==== Storage component + +The `Storage` component contains classes which enables the reading/writing of data to the hard disk. The figure below shows the structure of the `Storage` component. .Structure of the Storage Component image::StorageClassDiagram.png[width="800"] *API* : link:{repoURL}/src/main/java/seedu/address/storage/Storage.java[`Storage.java`] -The `Storage` component, +The `Storage` component does the following: -* can save `UserPref` objects in json format and read it back. -* can save the Address Book data in xml format and read it back. - -[[Design-Commons]] -=== Common classes - -Classes used by multiple components are in the `seedu.addressbook.commons` package. +* saves `UserPref` objects in json format and read it back. +* saves the system data in xml format and read it back. == Implementation @@ -246,7 +302,7 @@ This section describes some noteworthy details on how certain features are imple // tag::undoredo[] === Undo/Redo feature -==== Current Implementation +===== Current implementation The undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. @@ -264,26 +320,27 @@ Step 1. The user launches the application for the first time. The `VersionedAddr image::UndoRedoStartingStateListDiagram.png[width="800"] -Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state. +Step 2. The user executes `delete 5` command to delete the 5th volunteer in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state. image::UndoRedoNewCommand1StateListDiagram.png[width="800"] -Step 3. The user executes `add n/David ...` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`. +Step 3. The user executes `add n/David ...` to add a new volunteer. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`. image::UndoRedoNewCommand2StateListDiagram.png[width="800"] [NOTE] If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`. -Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state. +Step 4. The user now decides that adding the volunteer was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state. image::UndoRedoExecuteUndoStateListDiagram.png[width="800"] [NOTE] If the `currentStatePointer` is at index 0, pointing to the initial address book state, then there are no previous address book states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo. -The following sequence diagram shows how the undo operation works: +The following figure shows how the undo operation works: +.Sequence diagram of undo operation image::UndoRedoSequenceDiagram.png[width="800"] The `redo` command does the opposite -- it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the address book to that state. @@ -299,58 +356,686 @@ Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Sinc image::UndoRedoNewCommand4StateListDiagram.png[width="800"] -The following activity diagram summarizes what happens when a user executes a new command: +The following figure summarizes what happens when a user executes a new command: +.Activity diagram of new command execution image::UndoRedoActivityDiagram.png[width="650"] -==== Design Considerations +===== Design considerations -===== Aspect: How undo & redo executes +====== Aspect: How undo & redo executes -* **Alternative 1 (current choice):** Saves the entire address book. -** Pros: Easy to implement. -** Cons: May have performance issues in terms of memory usage. +* **Alternative 1 (current choice):** Save the entire address book. ++ +[cols="1,10"] +|=== +|*Pros*| Implementation is easy. +|*Cons*| May have performance issues in terms of memory usage. +|=== ++ * **Alternative 2:** Individual command knows how to undo/redo by itself. -** Pros: Will use less memory (e.g. for `delete`, just save the person being deleted). -** Cons: We must ensure that the implementation of each individual command are correct. -===== Aspect: Data structure to support the undo/redo commands ++ +[cols="1,10"] +|=== +|*Pros*| Use less memory (e.g. for `delete`, just save the person being deleted). +|*Cons*| Must ensure that the implementation of each individual command are correct. +|=== ++ -* **Alternative 1 (current choice):** Use a list to store the history of address book states. -** Pros: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project. -** Cons: Logic is duplicated twice. For example, when a new command is executed, we must remember to update both `HistoryManager` and `VersionedAddressBook`. -* **Alternative 2:** Use `HistoryManager` for undo/redo -** Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase. -** Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as `HistoryManager` now needs to do two different things. -// end::undoredo[] -// tag::dataencryption[] -=== [Proposed] Data Encryption +====== Aspect: Data structure to support the undo/redo commands -_{Explain here how the data encryption feature will be implemented}_ +* **Alternative 1 (current choice):** Use a list to store the history of address book states. ++ +[cols="1,10"] +|=== +|*Pros*| Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project. +|*Cons*| Logic is duplicated twice. For example, when a new command is executed, we must remember to update both `HistoryManager` and `VersionedAddressBook`. +|=== ++ -// end::dataencryption[] +* **Alternative 2:** Use `HistoryManager` for undo/redo ++ +[cols="1,10"] +|=== +|*Pros*| We do not need to maintain a separate list, and just reuse what is already in the codebase. +|*Cons*| Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as `HistoryManager` now needs to do two different things. +|=== ++ +// end::undoredo[] === Logging We are using `java.util.logging` package for logging. The `LogsCenter` class is used to manage the logging levels and logging destinations. -* The logging level can be controlled using the `logLevel` setting in the configuration file (See <>) -* The `Logger` for a class can be obtained using `LogsCenter.getLogger(Class)` which will log messages according to the specified logging level +* The logging level can be controlled using the `logLevel` setting in the configuration file. (See <>) +* The `Logger` for a class can be obtained using `LogsCenter.getLogger(Class)` which will log messages according to the specified logging level. * Currently log messages are output through: `Console` and to a `.log` file. *Logging Levels* -* `SEVERE` : Critical problem detected which may possibly cause the termination of the application -* `WARNING` : Can continue, but with caution -* `INFO` : Information showing the noteworthy actions by the App -* `FINE` : Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size +* `SEVERE` : Designates critical error events which may possibly cause the termination of the application. +* `WARNING` : Designates potentially harmful events which can be continued from, but with caution. +* `INFO` : Designates informational events that highlight noteworthy actions by the application. +* `FINE` : Designates event details that are not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size. [[Implementation-Configuration]] === Configuration Certain properties of the application can be controlled (e.g App name, logging level) through the configuration file (default: `config.json`). + +//tag::command-add[] +=== Add Volunteer command +The `add` command in the volunteer context is used to add a volunteer to the application. + +===== Current implementation + +This `add` command requires the `AddCommandParser` class to parse user input and add a volunteer with the details specified by the user. Currently, the details that are required by the user is Name, VolunteerId (NRIC), Gender, Birthday, Phone, Email and Address. + +`AddCommandParser` implements the `Parser` class which has the `Parser#parse()` operation. This operation will throw an error if the user input does not match the command format. + +The `add` command updates the context in `ModelManager` through `addVolunteer`. + +In addition to adding a volunteer, the `add` command also does the following: + +* Saves the current database state through `commitAddressBook` (for undo/redo functions). +* Raise a `OverviewPanelVolunteerUpdateEvent` to update the Overview panel for volunteer context. + +The figure below shows the sequence diagram for an `add` command in the volunteer context. + +image::command_add_sd.png[switch SD, 800] + +The following code snippet shows the fields that are required by the user when inputting the volunteer details for the `add` command: +```Java +public class AddCommand extends Command { + //... + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + requireNonNull(model); + + if (model.hasVolunteer(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_VOLUNTEER); + } + + model.addVolunteer(toAdd); + model.commitAddressBook(); + EventsCenter.getInstance().post(new OverviewPanelVolunteerUpdateEvent()); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + //... +} +``` + +===== Design considerations +====== Aspect: Choice of VolunteerId +* **Alternative 1 (current choice):** The use of unique identifier NRIC. ++ +[cols="1,10"] +|=== +|Pros| It is unique to each volunteer, and validates the uniqueness of a volunteer entry. +|Cons| It is larger in size than an integer, hence may incur more storage use. +|=== ++ + +* **Alternative 2:** Use of auto-incremented integer VolunteerId. ++ +[cols="1,10"] +|=== +|Pros| It requires less storage, and easier to maintain. +|Cons| It may not be a strong indicator of uniqueness. +|=== ++ + + +====== Aspect: Birthday Display Format +* **Alternative 1 (current choice):** Use a BirthdayUtil class to change format of date. ++ +[cols="1,10"] +|=== +|Pros| It requires less storage to store Birthday in original format. +|Cons| It requires BirthdayUtil to be invoked every time Birthday is to be displayed to the user. +|=== ++ + +* **Alternative 2:** Immediately store Birthday as preferred user friendly format. ++ +[cols="1,10"] +|=== +|Pros| It does not require BirthdayUtil to be invoked every time the Birthday is to be displayed to the user. +|Cons| It is difficult to maintain given that Birthday formats are of different length. Furthermore, requires more storage usage. +|=== ++ + +//end::command-add[] + +//tag::command-switch[] + +[[Implementation-Switch]] +=== Switch command + +The `switch` command is used to switch the context between 'volunteer' and 'event'. + +===== Current implementation + +This `switch` command requires the `SwitchCommandParser` class to parse user input and help determine the context to switch to. + + +`SwitchCommandParser` implements the `Parser` class which has the `Parser#parse()` operation. This operation will throw an error if the user input does not match the command format or is an invalid context to switch to. + +[NOTE] +There are only 2 valid contexts which a user can switch to with the command. + +v: 'volunteer' context + +e: 'event' context + +The `switch` command updates the context found in `ModelManager` before raising the context change event to update the UI. + +In addition to updating the context, the `switch` command also does the following: + +* Clears all predicates for volunteers, events and record lists. +* Resets the state pointer (for undo/redo functions). +* Raises `ContextChangeEvent` to update the UI. + +The following code snippet shows what the `switch` command does upon execution: +```Java +public class SwitchCommand extends Command { + //... + public SwitchCommand(String contextToSwitch) { + requireNonNull(contextToSwitch); + contextId = contextToSwitch; + } + + @Override + public CommandResult execute(Model model, CommandHistory history) { + requireNonNull(model); + + model.setCurrentContext(contextId); + model.updateFilteredVolunteerList(Model.PREDICATE_SHOW_ALL_VOLUNTEERS); + model.updateFilteredEventList(Model.PREDICATE_SHOW_ALL_EVENTS); + model.updateFilteredRecordList(Model.PREDICATE_SHOW_ALL_RECORDS); + model.resetStatePointer(); + + EventsCenter.getInstance().post(new ContextChangeEvent(contextId)); + return new CommandResult(String.format(MESSAGE_SUCCESS, model.getContextName())); + } +} +``` + +From the code snippet above, we see that upon calling the `SwitchCommand`, a contextId is set. +The contextId (which is retrieved from the user's input) is either 'e' for event or 'v' for volunteers. +This contextId will be used when the execute method is called. + +When the execute method is called, the context is set in the model via the 'setCurrentContext' method. +The model contains different methods to update the various lists. A predicate is passed to reset each of the lists to the initial state. + +The model also resets the state pointer so that the `undo` and `redo` functions will point to a fresh, new state. + +Lastly, the `EventsCenter` posts a new event so that the panels would update accordingly and display the relevant lists. + +The figure below is the sequence diagram to show how the `switch` command works when switching from volunteer to event context. + +.Simplified sequence diagram of switch command +image::command_switch_sd.png[switch SD, 800] + +===== Design considerations +====== Aspect: How context is maintained +* **Alternative 1 (current choice):** Create a new `Context` class. ++ +[cols="1,10"] +|=== +|Pros| Can support even more contexts in the future due to the flexibility of a class. +|Cons| Tedious to do as relevant methods have to be implemented in model. +|=== ++ + +* **Alternative 2:** Pass a hard-coded context id around. ++ +[cols="1,10"] +|=== +|Pros| No need to create a new object to handle the context. +|Cons| Difficult to maintain the id throughout the whole application. Any change in context id would require all the codes to be updated. +|=== ++ + + +// end::command-switch[] + + +// tag::exportcert[] +=== Export Volunteer Certificate + +The `exportcert` command enables the volunteer manager to export a PDF document detailing a volunteer's involvement with the organisation. +This is only possible when in the 'volunteer' context. The information included in the certificate are as follows: + +* Title: 'Certificate of Recognition' +* Date of export +* Volunteer name +* Volunteer ID +* List of events involved in - Event name, event ID, hours contributed, event start and event end dates +* Total hours contributed across all events + +Currently, the certificate will be exported to either of these two locations: + +* Folder named 'Certs' in the user's current working directory +* Direct to the user's current working directory (next to the .jar file) + +This is what the exported PDF certificate will look like: + +.Sample exported volunteer certificate +[.thumb] +image::CurrentVolunteerCert.png[width="500"] + +// tag::exportcert-sharan-ppp[] +===== Implementation + +The following activity diagram shows us the control flow of the `exportcert` feature. Analysing this diagram would be a good way to understand the intended functionality of this feature. + +.`exportcert` command activity diagram +[.thumb] +image::command_exportcert_ad.png[width="500"] + +The following steps were involved in this feature's implementation: + +1. Support for accepting `exportcert` command. +* Added an ExportCertCommand class that extends Command. +* Modified AddressBookParser class to accept an ExportCertCommand. + +2. Support for accepting arguments as part of the command. +* Modified ExportCertCommand class to take in an Index. +* Added an ExportCertCommandParser class that parses the Index argument. +* Modified the AddressBookParser to use the ExportCertCommandParser. + +3. Retrieve the right volunteer based on the given Index. +* Interact with the model to retrieve the filtered volunteer list. +* Get the Volunteer at the specified Index. + +4. Retrieve information on the events that this volunteer has been involved in, if any. +* Interact with the model to get the filtered record list, and filter the record list further to find the records with the volunteer's ID. +* Retrieve the event IDs from the relevant filtered records, along with the hours contributed. +* Get the Event that corresponds to the event ID, and retrieve its name, startDate and endDate for input into the certificate. + +5. Use of Apache PDFBox to create and export a volunteer certificate with the information retrieved. +* Involves the creation of a new https://pdfbox.apache.org/docs/2.0.2/javadocs/index.html?org/apache/pdfbox/pdmodel/PDDocument.html[PDDocument], +with a https://pdfbox.apache.org/docs/2.0.2/javadocs/org/apache/pdfbox/pdmodel/PDPage.html[PDPage] to write the content to. +* Writing of the information to a page content stream is then achieved using https://pdfbox.apache.org/docs/2.0.2/javadocs/org/apache/pdfbox/pdmodel/PDPageContentStream.html[PDPageContentStream]. + +The following sequence diagrams show how the `exportcert` operation will be executed for a valid command `exportcert 1`. Analyse these diagrams to achieve a more detailed understanding of the internal interactions involved in the execution of this feature. + +.Sequence diagram for `exportcert 1` with simplified ExportCertCommand execution +image::command_exportcert_sd_1.png[exportcert SD, 800] + +The next sequence diagram below looks at the ExportCertCommand's execution in detail, including it's interaction with the model. + +.Detailed sequence diagram for ExportCertCommand execution +image::command_exportcert_sd_2.png[exportcert SD, 650] + +===== Design Considerations + +====== Aspect: Medium of presentation + +* *Alternative 1 (current choice):* Export as PDF ++ +[cols="1,10"] +|=== +|*Pros*| Exports volunteer details in a convenient format for immediate use and distribution. +|*Cons*| PDF template has to be preset within the application. +|=== ++ + +* *Alternative 2:* Display volunteer data in a window within the application ++ +[cols="1,10"] +|=== +|*Pros*| Allows the volunteer manager flexibility as to what to do with the volunteer details. This could include manually inputting it into an existing certificate creation application, or a document template. +|*Cons*| Requires more manual work on the volunteer manager's side, especially when the process can be automated to enhance his/her productivity. Certificate templates are also infrequently updated, and thus the costs in terms of efficiency outweigh the benefits in terms of flexibility. +|=== ++ + + +====== Aspect: Choice of PDF creation tool + +* *Alternative 1 (current choice):* Apache PDFBox ++ +[cols="1,10"] +|=== +|*Pros*| Open source, offers more specific functionality for PDFs than Apache FOP, and covers all of the pdf creation and manipulation functionality required for this feature. +|*Cons*| Not the most efficient for creating PDFs (refer to http://abhishekkumararya.blogspot.com/2013/09/comparison-of-java-based-pdf-generation.html[this comparison study]). +|=== ++ + +* *Alternative 2:* Apache FOP ++ +[cols="1,10"] +|=== +|*Pros*| Open source, allows for conversion and formatting of XML data to PDF. +|*Cons*| Resource intensive, not the most efficient for PDF creation, and lacks features such as updating and merging PDFs. +|=== ++ + +* *Alternative 3:* iText ++ +[cols="1,10"] +|=== +|*Pros*| Fastest of the lot for PDF generation (refer to http://abhishekkumararya.blogspot.com/2013/09/comparison-of-java-based-pdf-generation.html[this comparison study]). +|*Cons*| Now only available as a free trial, and requires a license for extended use. +|=== ++ + + +====== Aspect: Choice of export location + +* **Alternative 1 (current choice):** Export to the user's current working directory ++ +[cols="1,10"] +|=== +|*Pros*| Putting the files relative to where the app is allows the user to locate, manage and access the exports easily as this is a portable app. The app jar and the exported files can be shifted to different locations together easily as well. +|*Cons*| Navigating to this directory would be necessary if he/she wishes to access the files independent of using the application. +|=== ++ + +* **Alternative 2:** Export to the user's Desktop ++ +[cols="1,10"] +|=== +|*Pros*| Easy to access files when not using the application. +|*Cons*| As it is a portable app, it may be cumbersome to keep navigating to the Desktop to access the exports when using the application. It also becomes harder to move the app jar and exports together from place to place. +|=== ++ + +* **Alternative 3:** Allow the user to specify the export filepath as an argument ++ +[cols="1,10"] +|=== +|*Pros*| Allows for greater customisability, thus catering to each user's unique needs. +|*Cons*| Requires user to have accurate prior knowledge of the machine's filepath format. Moreover, support for all possible OS filepath formats within the application may not be possible as well (e.g. custom OS filepath). +|=== ++ + + +====== Aspect: Organisation of PDF generation code + +* **Alternative 1 (current choice):** Encapsulate within a `CertGenerator` class with exposed public method(s) ++ +[cols="1,10"] +|=== +|*Pros*| Allows for separation of concerns as handling command result or exceptions & retrieving volunteer data is separated from the creation, population and export of the certificate. Also allows for future extension of the PDF generation feature (e.g. generating event reports) through adding a `ExportPdf` abstract class or interface with `generatePdf`, `populatePdf` and `exportPdf` methods to be implemented. +|*Cons*| Introduces inherent coupling between `ExportCertCommand` and `CertGenerator` classes as currently, only `ExportCertCommand` includes the certificate generation functionality. +|=== ++ + +* **Alternative 2:** Leave PDF generation code inside a method within the `ExportCertCommand` class ++ +[cols="1,10"] +|=== +|*Pros*| Allows the certificate generation code to reside exactly where it is used, as the certificate generation functionality is currently only used by `ExportCertCommand`. +|*Cons*| Causes a low level of cohesion by packaging different functionalities within `ExportCertCommand`. The functionality to export PDFs also remains unabstracted, and thus extending the functionality to create e.g. event report PDFs would require repetition of the PDF generation code. +|=== ++ +// end::exportcert-sharan-ppp[] + +====== Aspect: Choice of additional details for identifying volunteer from certificate + +* **Alternative 1 (current choice):** Use Volunteer's NRIC ++ +[cols="1,10"] +|=== +|*Pros*| Adds credibility to the certificate by displaying something that is unique to each volunteer, and can be recovered easily given the volunteer's name or other personal information. +|*Cons*| Requires more space as each NRIC has to be represented as string of length 9 or a 7-digit integer. +|=== ++ + +* **Alternative 2:** Use a Volunteer ID ++ +[cols="1,10"] +|=== +|*Pros*| Achieves the intended purpose (additional volunteer identification), while encompassing the ability to be auto-incremented. +|*Cons*| Hard to recover, even if additional information about the volunteer is provided. It would also be meaningless to a third person to whom the certificate is presented for verification purposes. +|=== ++ + +// end::exportcert[] + +// tag::eventmanagement[] +=== Auto-incremented event ID + +The auto-incremented event ID field is used by the `Record` class to identify unique events. An integer ID field is used because +the alternative method of identifying unique events based on multiple `Event` attribute fields would be computationally inefficient. + +===== Current implementation + +The auto-incremented event ID field is facilitated by the `Event` class. The `Event` class +keeps track of the highest ID in the system. Additionally, it implements two different constructors for different situations: + +* `Event(Name name, Location location, Date startDate, Date endDate, + Time startTime, Time endTime, Description description, Set tags)` ++ +This constructor is used when working with an event that does not yet exist in the system (e.g. adding a new event). ++ +It increments the current highest event ID in the system and assigns that value to the new event that is created. This behaviour is illustrated in the code snippet of the `Event` class below. ++ +``` Java +public Event(Name name, Location location, Date startDate, Date endDate, Time startTime, Time endTime, Description description, Set tags) { + ... + incrementMaxId(); + this.eventId = new EventId(maxId); + ... +} + +private void incrementMaxId() { + maxId += 1; +} +``` + +* `Event(EventId eventId, Name name, Location location, Date startDate, Date endDate, + Time startTime, Time endTime, Description description, Set tags)` ++ +This constructor is used when working with an event that already exists in the system (e.g. loading data from XML file or editing an existing event). ++ +It checks whether the ID of the event being initialised is greater than the current highest ID in the system. +If this condition is true, the current highest event ID value will be replaced by the ID of the event being initialised. +This behaviour is illustrated in the code snippet of the `Event` class below. ++ +``` Java +public Event(Name name, Location location, Date startDate, Date endDate, Time startTime, Time endTime, Description description, Set tags) { + ... + if (isEventIdGreaterThanMaxId(eventId.id)) { + replaceMaxIdWithEventId(eventId.id); + } + ... +} + +private void replaceMaxIdWithEventId(int eventId) { + maxId = eventId; +} +``` + +===== Design considerations +====== Aspect: How event ID is generated +* *Alternative 1 (current choice):* Increment from highest event ID ++ +[cols="1,10"] +|=== +|*Pros*| Implementation is easy. +|*Cons*| Maintained highest event ID may be susceptible to overwrite and become desynchronised. +|=== ++ +* *Alternative 2:* Randomly generated unique event ID ++ +[cols="1,10"] +|=== +|*Pros*| Not dependent on a maintained highest event ID variable (single point of failure). +|*Cons*| Requires keeping track of all existing event IDs to ensure uniqueness. +|=== ++ + +// end::eventmanagement[] + +//tag::command-manage[] +[[Implementation-Manage]] +=== Manage command + +The `manage` command is used in the 'event' context to manage the volunteering records for an event. + + +===== Current implementation +This `manage` command requires the `ManageCommandParser` class to parse user input and determine which event to manage. + + +`ManageCommandParser` implements the `Parser` class which has the `Parser#parse()` operation. This operation will throw an error if the user input is an invalid event id. + +The `manage` command updates the context found in `ModelManager` through the `model#switchToRecordContext()` function. + + +In addition to updating the context, the `manage` command also does the following: + +* Clears all predicates for volunteer list. +* Filters the existing records by the selected event. +* Resets the state pointer (for undo/redo functions). +* Raises `RecordChangeEvent` to set the selected event. +* Raises `ContextChangeEvent` to update the UI. + +The following code snippet shows what the `manage` command does upon execution: + +```Java +public class ManageCommand extends Command { + //... + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + requireNonNull(model); + + List filteredEventList = model.getFilteredEventList(); + model.updateFilteredVolunteerList(PREDICATE_SHOW_ALL_VOLUNTEERS); + + if (targetIndex.getZeroBased() >= filteredEventList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_EVENT_DISPLAYED_INDEX); + } + + model.switchToRecordContext(); + model.setSelectedEvent(filteredEventList.get(targetIndex.getZeroBased())); + model.updateFilteredRecordList(new RecordContainsEventIdPredicate( + filteredEventList.get(targetIndex.getZeroBased()).getEventId() + )); + model.resetStatePointer(); + + + EventsCenter.getInstance().post(new RecordChangeEvent( + filteredEventList.get(targetIndex.getZeroBased()))); + EventsCenter.getInstance().post(new ContextChangeEvent(model.getContextId())); + + return new CommandResult(String.format(MESSAGE_MANAGE_EVENT_SUCCESS, + filteredEventList.get(targetIndex.getZeroBased()).getName().fullName) + + " [" + targetIndex.getOneBased() + "]"); + + } + //... +} +``` + +From the code snippet above, we see that the current state of event list from the model is stored into another list called 'filteredEventList'. +Storing the events in another list is done so that the list can be easily referenced in later parts of the code. + +The volunteer list in the model is updated with the predicate so that it now contains the list of all volunteers in the system. + +A quick check is done to ensure that the user input is valid. Otherwise, an exception is thrown. + +If the user input is valid, the application changes to the record context. Then, the selected event by the user is stored in the model. +In addition, the model resets the state pointer so that the `undo` and `redo` functions will point to a fresh, new state. + +Lastly, all the relevant UI is updated by posting events via the `EventsCenter`. + +The figure below is the sequence diagram to show how the `switch` command works when switching from volunteer to event context. + +.Simplified sequence diagram for manage command +image::command_manage_sd.png[manage SD, 800] + +===== Design considerations +====== Aspect: Context switching (to volunteering records) +* **Alternative 1 (current choice):** Utilize `Context` class used in the `switch` function. (See <>) ++ +[cols="1,10"] +|=== +|Pros| No need to create a new class to change context. +|Cons| Have to create a new method in `Context` class to handle parsed user input. +|=== ++ + +* **Alternative 2:** Pass event and volunteer objects via `LogicManager`. ++ +[cols="1,10"] +|=== +|Pros| Implementation is easy. +|Cons| Classes becomes tightly coupled. The UI component would have access to methods it does not need. +|=== ++ + +//end::command-manage[] + + +//tag::command-overview[] +[[Implementation-Overview]] +=== Overview command +The `overview` command is used in the 'event' or 'volunteer' context to show statistics for the number of types of events and volunteer distribution. + +===== Current implementation +The `overview` command raises a `OverviewPanelChangedEvent` to start calculating statistical data and to +update the UI. + +Because of the volatile nature of the data (it can change when attributes of events or volunteers are changed), the data is not stored persistently in the `ModelManager`. + +Instead, whenever the `OverviewPanel` UI class detects an `OverviewPanelChangedEvent`, it calls on the `Overview` to provide it with updated statistics. + +The figure below is the sequence diagram to show how the `overview` command works when running from the 'event' context. +Note that the `OverviewPanel` calls the calculateNumOfEvents and calculateVolunteerDemographics methods in `Overview` class. + +.Simplified sequence diagram for `overview` command +image::command_overview_sd.png[overview SD, 800] + +In the calculateNumOfEvents method, events are categorised into 3 events types: + +* Upcoming (events that have yet to happen). +* Ongoing (events that are currently happening). +* Completed (events that have already happened). + +The categorisation process can be found in the `DateTimeUtil` class in the getEventStatus method. +The start to end period of each event is compared with the current date and time to determine its category. +This behaviour is illustrated in the code snippet below. + +``` Java +public static int getEventStatus(Date startDate, Time startTime, Date endDate, Time endTime) { + ... + if (now.compareTo(start) < 0) { + return UPCOMING_EVENT; + } else if (now.compareTo(start) >= 0 && now.compareTo(end) <= 0) { + return ONGOING_EVENT; + } else { + return COMPLETED_EVENT; + } + ... +} +``` + +In the calculateVolunteerDemographics method, the ages of volunteers are derived from their birthdates instead of being stored in the system. + +===== Design considerations + +====== Aspect: How statistics are aggregated +* **Alternative 1 (current choice):** Calculate statistics from scratch using existing volunteers and events ++ +[cols="1,10"] +|=== +|Pros| No need to store and maintain volatile statistical data. +|Cons| Requires heavier processing every time statistics are aggregated. +|=== ++ + +* **Alternative 2:** Store and maintain statistics after each operation ++ +[cols="1,10"] +|=== +|Pros| No need for heavy computation as a result of building statistics from scratch. +|Cons| Have to propagate changes to statistical data after changes to volunteers and events. +|=== ++ +//end::command-overview[] + + == Documentation We use asciidoc for writing documentation. @@ -358,16 +1043,16 @@ We use asciidoc for writing documentation. [NOTE] We chose asciidoc over Markdown because asciidoc, although a bit more complex than Markdown, provides more flexibility in formatting. -=== Editing Documentation +=== Editing documentation See <> to learn how to render `.adoc` files locally to preview the end result of your edits. Alternatively, you can download the AsciiDoc plugin for IntelliJ, which allows you to preview the changes you have made to your `.adoc` files in real-time. -=== Publishing Documentation +=== Publishing documentation See <> to learn how to deploy GitHub Pages using Travis. -=== Converting Documentation to PDF format +=== Converting documentation to PDF format We use https://www.google.com/chrome/browser/desktop/[Google Chrome] for converting documentation to PDF format, as Chrome's PDF engine preserves hyperlinks used in webpages. @@ -382,7 +1067,7 @@ Here are the steps to convert the project documentation files to PDF format. image::chrome_save_as_pdf.png[width="300"] [[Docs-SiteWideDocSettings]] -=== Site-wide Documentation Settings +=== Site-wide documentation settings The link:{repoURL}/build.gradle[`build.gradle`] file specifies some project-specific https://asciidoctor.org/docs/user-manual/#attributes[asciidoc attributes] which affects how all documentation files within this project are rendered. @@ -412,7 +1097,7 @@ This will render the SE-EDU navigation bar at the top of the page, and add some |=== [[Docs-PerFileDocSettings]] -=== Per-file Documentation Settings +=== Per-file documentation settings Each `.adoc` file may also specify some file-specific https://asciidoctor.org/docs/user-manual/#attributes[asciidoc attributes] which affects how the file is rendered. @@ -440,7 +1125,7 @@ _{asterisk} Official SE-EDU projects only_ |=== -=== Site Template +=== Site template The files in link:{repoURL}/docs/stylesheets[`docs/stylesheets`] are the https://developer.mozilla.org/en-US/docs/Web/CSS[CSS stylesheets] of the site. You can modify them to change some properties of the site's design. @@ -458,7 +1143,9 @@ The SE-EDU team does not provide support for modified template files. [[Testing]] == Testing -=== Running Tests +Testing is done to verify how the application runs, responds and process commands given by the Admin, to check if the app runs with its intended behavior. + +=== Running tests There are three ways to run tests. @@ -499,7 +1186,7 @@ e.g. `seedu.address.storage.StorageManagerTest` e.g. `seedu.address.logic.LogicManagerTest` -=== Troubleshooting Testing +=== Troubleshooting testing **Problem: `HelpWindowTest` fails with a `NullPointerException`.** * Reason: One of its dependencies, `HelpWindow.html` in `src/main/resources/docs` is missing. @@ -507,35 +1194,35 @@ e.g. `seedu.address.logic.LogicManagerTest` == Dev Ops -=== Build Automation +=== Build automation See <> to learn how to use Gradle for build automation. -=== Continuous Integration +=== Continuous integration We use https://travis-ci.org/[Travis CI] and https://www.appveyor.com/[AppVeyor] to perform _Continuous Integration_ on our projects. See <> and <> for more details. -=== Coverage Reporting +=== Coverage reporting We use https://coveralls.io/[Coveralls] to track the code coverage of our projects. See <> for more details. -=== Documentation Previews +=== Documentation previews When a pull request has changes to asciidoc files, you can use https://www.netlify.com/[Netlify] to see a preview of how the HTML version of those asciidoc files will look like when the pull request is merged. See <> for more details. -=== Making a Release +=== Making a release -Here are the steps to create a new release. +Here are the steps to create a new release: . Update the version number in link:{repoURL}/src/main/java/seedu/address/MainApp.java[`MainApp.java`]. . Generate a JAR file <>. . Tag the repo with the version number. e.g. `v0.1` . https://help.github.com/articles/creating-releases/[Create a new release using GitHub] and upload the JAR file you created. -=== Managing Dependencies +=== Managing dependencies -A project often depends on third-party libraries. For example, Address Book depends on the http://wiki.fasterxml.com/JacksonHome[Jackson library] for XML parsing. Managing these _dependencies_ can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than these alternatives. + -a. Include those libraries in the repo (this bloats the repo size) + -b. Require developers to download those libraries manually (this creates extra work for developers) +A project often depends on third-party libraries. For example, Address Book depends on the http://wiki.fasterxml.com/JacksonHome[Jackson library] for XML parsing. Managing these _dependencies_ can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than the following alternatives: + +1) Include those libraries in the repo (this bloats the repo size) + +2) Require developers to download those libraries manually (this creates extra work for developers) [[GetStartedProgramming]] [appendix] @@ -587,9 +1274,9 @@ Do take a look at <> before attempting to modify the `Model` compo * Hints ** The link:{repoURL}/src/main/java/seedu/address/model/Model.java[`Model`] and the link:{repoURL}/src/main/java/seedu/address/model/AddressBook.java[`AddressBook`] API need to be updated. ** Think about how you can use SLAP to design the method. Where should we place the main logic of deleting tags? -** Find out which of the existing API methods in link:{repoURL}/src/main/java/seedu/address/model/AddressBook.java[`AddressBook`] and link:{repoURL}/src/main/java/seedu/address/model/person/Person.java[`Person`] classes can be used to implement the tag removal logic. link:{repoURL}/src/main/java/seedu/address/model/AddressBook.java[`AddressBook`] allows you to update a person, and link:{repoURL}/src/main/java/seedu/address/model/person/Person.java[`Person`] allows you to update the tags. +** Find out which of the existing API methods in link:{repoURL}/src/main/java/seedu/address/model/AddressBook.java[`AddressBook`] and link:{repoURL}/src/main/java/seedu/address/model/volunteer/Person.java[`Person`] classes can be used to implement the tag removal logic. link:{repoURL}/src/main/java/seedu/address/model/AddressBook.java[`AddressBook`] allows you to update a volunteer, and link:{repoURL}/src/main/java/seedu/address/model/volunteer/Person.java[`Person`] allows you to update the tags. * Solution -** Implement a `removeTag(Tag)` method in link:{repoURL}/src/main/java/seedu/address/model/AddressBook.java[`AddressBook`]. Loop through each person, and remove the `tag` from each person. +** Implement a `removeTag(Tag)` method in link:{repoURL}/src/main/java/seedu/address/model/AddressBook.java[`AddressBook`]. Loop through each volunteer, and remove the `tag` from each volunteer. ** Add a new API method `deleteTag(Tag)` in link:{repoURL}/src/main/java/seedu/address/model/ModelManager.java[`ModelManager`]. Your link:{repoURL}/src/main/java/seedu/address/model/ModelManager.java[`ModelManager`] should call `AddressBook#removeTag(Tag)`. ** Add new tests for each of the new public methods that you have added. ** See this https://github.com/se-edu/addressbook-level4/pull/790[PR] for the full solution. @@ -598,12 +1285,12 @@ Do take a look at <> before attempting to modify the `Model` compo [discrete] ==== `Ui` component -*Scenario:* You are in charge of `ui`. During a beta testing session, your team is observing how the users use your address book application. You realize that one of the users occasionally tries to delete non-existent tags from a contact, because the tags all look the same visually, and the user got confused. Another user made a typing mistake in his command, but did not realize he had done so because the error message wasn't prominent enough. A third user keeps scrolling down the list, because he keeps forgetting the index of the last person in the list. Your job is to implement improvements to the UI to solve all these problems. +*Scenario:* You are in charge of `ui`. During a beta testing session, your team is observing how the users use your address book application. You realize that one of the users occasionally tries to delete non-existent tags from a contact, because the tags all look the same visually, and the user got confused. Another user made a typing mistake in his command, but did not realize he had done so because the error message wasn't prominent enough. A third user keeps scrolling down the list, because he keeps forgetting the index of the last volunteer in the list. Your job is to implement improvements to the UI to solve all these problems. [TIP] Do take a look at <> before attempting to modify the `UI` component. -. Use different colors for different tags inside person cards. For example, `friends` tags can be all in brown, and `colleagues` tags can be all in yellow. +. Use different colors for different tags inside volunteer cards. For example, `friends` tags can be all in brown, and `colleagues` tags can be all in yellow. + **Before** + @@ -696,17 +1383,17 @@ By creating this command, you will get a chance to learn how to implement a feat *Scenario:* You are a software maintainer for `addressbook`, as the former developer team has moved on to new projects. The current users of your application have a list of new feature requests that they hope the software will eventually have. The most popular request is to allow adding additional comments/notes about a particular contact, by providing a flexible `remark` field for each contact, rather than relying on tags alone. After designing the specification for the `remark` command, you are convinced that this feature is worth implementing. Your job is to implement the `remark` command. ==== Description -Edits the remark for a person specified in the `INDEX`. + +Edits the remark for a volunteer specified in the `INDEX`. + Format: `remark INDEX r/[REMARK]` Examples: * `remark 1 r/Likes to drink coffee.` + -Edits the remark for the first person to `Likes to drink coffee.` +Edits the remark for the first volunteer to `Likes to drink coffee.` * `remark 1 r/` + -Removes the remark for the first person. +Removes the remark for the first volunteer. -==== Step-by-step Instructions +==== Step-by-step instructions ===== [Step 1] Logic: Teach the app to accept 'remark' which does nothing Let's start by teaching the application how to parse a `remark` command. We will add the logic of `remark` later. @@ -738,7 +1425,7 @@ for `RemarkCommandParser`. . Modify link:{repoURL}/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java[`AddressBookParserTest`] to test that the correct command is generated according to the user input. ===== [Step 3] Ui: Add a placeholder for remark in `PersonCard` -Let's add a placeholder on all our link:{repoURL}/src/main/java/seedu/address/ui/PersonCard.java[`PersonCard`] s to display a remark for each person later. +Let's add a placeholder on all our link:{repoURL}/src/main/java/seedu/address/ui/PersonCard.java[`PersonCard`] s to display a remark for each volunteer later. **Main:** @@ -750,11 +1437,11 @@ Let's add a placeholder on all our link:{repoURL}/src/main/java/seedu/address/ui . Modify link:{repoURL}/src/test/java/guitests/guihandles/PersonCardHandle.java[`PersonCardHandle`] so that future tests can read the contents of the remark label. ===== [Step 4] Model: Add `Remark` class -We have to properly encapsulate the remark in our link:{repoURL}/src/main/java/seedu/address/model/person/Person.java[`Person`] class. Instead of just using a `String`, let's follow the conventional class structure that the codebase already uses by adding a `Remark` class. +We have to properly encapsulate the remark in our link:{repoURL}/src/main/java/seedu/address/model/volunteer/Person.java[`Person`] class. Instead of just using a `String`, let's follow the conventional class structure that the codebase already uses by adding a `Remark` class. **Main:** -. Add `Remark` to model component (you can copy from link:{repoURL}/src/main/java/seedu/address/model/person/Address.java[`Address`], remove the regex and change the names accordingly). +. Add `Remark` to model component (you can copy from link:{repoURL}/src/main/java/seedu/address/model/volunteer/Address.java[`Address`], remove the regex and change the names accordingly). . Modify `RemarkCommand` to now take in a `Remark` instead of a `String`. **Tests:** @@ -762,12 +1449,12 @@ We have to properly encapsulate the remark in our link:{repoURL}/src/main/java/s . Add test for `Remark`, to test the `Remark#equals()` method. ===== [Step 5] Model: Modify `Person` to support a `Remark` field -Now we have the `Remark` class, we need to actually use it inside link:{repoURL}/src/main/java/seedu/address/model/person/Person.java[`Person`]. +Now we have the `Remark` class, we need to actually use it inside link:{repoURL}/src/main/java/seedu/address/model/volunteer/Person.java[`Person`]. **Main:** -. Add `getRemark()` in link:{repoURL}/src/main/java/seedu/address/model/person/Person.java[`Person`]. -. You may assume that the user will not be able to use the `add` and `edit` commands to modify the remarks field (i.e. the person will be created without a remark). +. Add `getRemark()` in link:{repoURL}/src/main/java/seedu/address/model/volunteer/Person.java[`Person`]. +. You may assume that the user will not be able to use the `add` and `edit` commands to modify the remarks field (i.e. the volunteer will be created without a remark). . Modify link:{repoURL}/src/main/java/seedu/address/model/util/SampleDataUtil.java/[`SampleDataUtil`] to add remarks for the sample data (delete your `addressBook.xml` so that the application will load the sample data when you launch it.) ===== [Step 6] Storage: Add `Remark` field to `XmlAdaptedPerson` class @@ -782,11 +1469,11 @@ We now have `Remark` s for `Person` s, but they will be gone when we exit the ap . Fix `invalidAndValidPersonAddressBook.xml`, `typicalPersonsAddressBook.xml`, `validAddressBook.xml` etc., such that the XML tests will not fail due to a missing `` element. ===== [Step 6b] Test: Add withRemark() for `PersonBuilder` -Since `Person` can now have a `Remark`, we should add a helper method to link:{repoURL}/src/test/java/seedu/address/testutil/PersonBuilder.java[`PersonBuilder`], so that users are able to create remarks when building a link:{repoURL}/src/main/java/seedu/address/model/person/Person.java[`Person`]. +Since `Person` can now have a `Remark`, we should add a helper method to link:{repoURL}/src/test/java/seedu/address/testutil/PersonBuilder.java[`PersonBuilder`], so that users are able to create remarks when building a link:{repoURL}/src/main/java/seedu/address/model/volunteer/Person.java[`Person`]. **Tests:** -. Add a new method `withRemark()` for link:{repoURL}/src/test/java/seedu/address/testutil/PersonBuilder.java[`PersonBuilder`]. This method will create a new `Remark` for the person that it is currently building. +. Add a new method `withRemark()` for link:{repoURL}/src/test/java/seedu/address/testutil/PersonBuilder.java[`PersonBuilder`]. This method will create a new `Remark` for the volunteer that it is currently building. . Try and use the method on any sample `Person` in link:{repoURL}/src/test/java/seedu/address/testutil/TypicalPersons.java[`TypicalPersons`]. ===== [Step 7] Ui: Connect `Remark` field to `PersonCard` @@ -805,13 +1492,13 @@ We now have everything set up... but we still can't modify the remarks. Let's fi **Main:** -. Replace the logic in `RemarkCommand#execute()` (that currently just throws an `Exception`), with the actual logic to modify the remarks of a person. +. Replace the logic in `RemarkCommand#execute()` (that currently just throws an `Exception`), with the actual logic to modify the remarks of a volunteer. **Tests:** . Update `RemarkCommandTest` to test that the `execute()` logic works. -==== Full Solution +==== Full solution See this https://github.com/se-edu/addressbook-level4/pull/599[PR] for the step-by-step solution. @@ -820,104 +1507,325 @@ See this https://github.com/se-edu/addressbook-level4/pull/599[PR] for the step- *Target user profile*: -* has a need to manage a significant number of contacts +* has a need to manage a significant number of volunteers and social welfare events * prefer desktop apps over other types * can type fast * prefers typing over mouse input * is reasonably comfortable using CLI apps -*Value proposition*: manage contacts faster than a typical mouse/GUI driven app +*Value proposition*: manage volunteers and events faster than a typical mouse/GUI driven app, and derive insights from them [appendix] == User Stories Priorities: High (must have) - `* * \*`, Medium (nice to have) - `* \*`, Low (unlikely to have) - `*` -[width="59%",cols="22%,<23%,<25%,<30%",options="header",] +[width="100%",cols="21%,<23%,<25%,<30%",options="header",] |======================================================================= |Priority |As a ... |I want to ... |So that I can... -|`* * *` |new user |see usage instructions |refer to instructions when I forget how to use the App +|`* * *` |new manager |see usage instructions |refer to instructions when I forget how to use the App -|`* * *` |user |add a new person | +|`* * *` |manager |register a new volunteer |begin tracking their volunteer work & hours -|`* * *` |user |delete a person |remove entries that I no longer need +|`* * *` |manager |view a volunteer's details |track their volunteer work & hours -|`* * *` |user |find a person by name |locate details of persons without having to go through the entire list +|`* * *` |manager |update volunteer details |keep their details updated for administrative & other purposes -|`* *` |user |hide <> by default |minimize chance of someone else seeing them by accident +|`* *` |manager |archive volunteer details |stash away unnecessary volunteer records, yet have the option of restoring them if needed -|`*` |user with many persons in the address book |sort persons by name |locate a person easily -|======================================================================= +|`* *` |manager |restore volunteer record |restore volunteer details that were archived -_{More to be added}_ +|`* * *` |manager |delete volunteer record |permanently remove volunteer record from database -[appendix] -== Use Cases +|`* *` |manager |import volunteer record details |add multiple volunteer data into the database -(For all use cases below, the *System* is the `AddressBook` and the *Actor* is the `user`, unless specified otherwise) +|`*` |manager |export volunteer record details |have a backup of the volunteer records -[discrete] -=== Use case: Delete person +|`* * *` |manager |create new event |have a record of the event details -*MSS* +|`* * *` |manager |update event details |ensure that event details are kept up to date -1. User requests to list persons -2. AddressBook shows a list of persons -3. User requests to delete a specific person in the list -4. AddressBook deletes the person -+ -Use case ends. +|`* * *` |manager |view event details |verify the details of the event -*Extensions* +|`* * *` |manager |delete event details |remove the event from the list if event details were entered wrongly or cancelled -[none] -* 2a. The list is empty. -+ -Use case ends. +|`* *` |manager |archive event details |stash away event records yet have the option of restoring them -* 3a. The given index is invalid. -+ -[none] -** 3a1. AddressBook shows an error message. -+ -Use case resumes at step 2. +|`* *` |manager |restore event details |restore event details that were archived -_{More to be added}_ +|`* *` |manager |import event data |add multiple events at once -[appendix] -== Non Functional Requirements +|`*` |manager |export event data |have a backup of event details -. Should work on any <> as long as it has Java `9` or higher installed. -. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage. -. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. +|`* * *` |manager |add volunteer hours to volunteer profiles |keep track of the number of hours spent by the volunteer volunteering -_{More to be added}_ +|`* * *` |manager |edit volunteer hours in volunteer profiles |maintain accuracy of information pertaining to volunteer work -[appendix] -== Glossary +|`*` |manager |export certification document from volunteers’ data |provide volunteers with official acknowledgement of service rendered to organization + +|`* *` |manager |view spread of volunteers across events |determine which are the more popular events -[[mainstream-os]] Mainstream OS:: -Windows, Linux, Unix, OS-X +|`* *` |manager |view demographics of volunteers |know what my volunteer profiles are like -[[private-contact-detail]] Private contact detail:: -A contact detail that is not meant to be shared with others +|`* *` |manager |auto-complete commands |execute commands more efficiently +|======================================================================= [appendix] -== Product Survey +== Use Cases -*Product Name* +(For all use cases below, the *System* is the `AddressBook` and the *Actor* is the `user`, unless specified otherwise) -Author: ... -Pros: +[width="100%",cols="100%",options="header",] +|======================================================================= +|Use Cases +a|*UC01:* Register new volunteer + +*Actor:* Admin + +*Precondition(s):* Admin is logged in + +*Guarantee(s):* + +* New user will be created only if data entered is valid and there is sufficient memory space to store the new user + + +*MSS:* + + . Admin chooses to add a new volunteer + . Application requests for details of the volunteer + . Admin enters and submits the requested details + . Application creates the volunteer and notifies Admin of success + + Use case ends. + + +*Extensions:* + + + * 3a. The entered data is invalid + ** 3a1. Application shows an error message that the entered data is invalid + + Use case resumes from step 3. +a|*UC02:* View volunteer details + +*Actor:* Admin + +*Precondition(s):* Admin is logged in + +*Guarantee(s):* + +*MSS:* + + . Admin requests to list all volunteers + . Application displays a list of all volunteers + . Admin requests to view a volunteer profile at a specific index in the list + . Application displays the volunteer profile + + Use case ends. + + +*Extensions:* + + * 2a. The volunteer list is empty + ** 2a1. Application shows an error message that volunteer list is empty + + Use case ends. + * 3a. The given index is invalid + ** 3a1. Application shows an error message that the index given is invalid + + Use case resumes from step 2. +a|*UC03:* Update volunteer details + +*Actor:* Admin + +*Precondition(s):* Admin is logged in + +*Guarantee(s):* + +*MSS:* + + . Admin requests to list all volunteers + . Application displays a list of all volunteers + . Admin enters the index and updated details of the volunteer to be changed + . Application updates the volunteer details and notifies of the successful update + + Use case ends. + + +*Extensions:* + + * 2a. The volunteer list is empty + ** 2a1. Application shows an error message that volunteer list is empty + + Use case ends. + * 3a. The given index is invalid + ** 3a1. Application shows an error message that the index given is invalid + + Use case resumes from step 2. + * 3b. The given details are invalid + ** 3b1. Application shows an error message that the details given are invalid + + Use case resumes at step 2. +a|*UC04:* Delete volunteer record + +*Actor:* Admin + +*Precondition(s):* Admin is logged in + +*Guarantee(s):* + + + * Volunteer record will be deleted only if index specified is valid + + +*MSS:* + + . Admin requests to list all volunteers + . Application displays a list of all volunteers + . Admin requests to delete a volunteer at a specific index in the list + . Application deletes the volunteer + . Application displays a successful deletion message to Admin + + Use case ends. + + +*Extensions:* + + * 2a. The volunteer list is empty + ** 2a1. Application shows an error message that volunteer list is empty + + Use case ends. + * 3a. The given index is invalid + ** 3a1. Application shows an error message that the index given is invalid + + Use case resumes from step 2. +a|*UC05:* Create new event + +*Actor:* Admin + +*Precondition(s):* Admin is logged in + +*Guarantee(s):* + +*MSS:* + + . Admin requests to create a new event + . Application requests for details of the event + . Admin enters details of the event to be created + . Application creates the event and shows successful creation message + + Use case ends. + + +*Extensions:* + + * 2a. The given details is invalid + ** 2a1. Application shows an error message that given details is invalid + + Use case resumes from step 1. +a|*UC06:* Update event details + +*Actor:* Admin + +*Precondition(s):* Admin is logged in + +*Guarantee(s):* + +*MSS:* + + . Admin requests to list all events + . Application displays a list of all events + . Admin enters the index and updated details of the event to be changed + . Application updates the event details and notifies of the successful update + + Use case ends. + + +*Extensions:* + + * 2a. The event list is empty + ** 2a1. Application shows an error message that event list is empty + + Use case ends. + * 3a. The given index is invalid + ** 3a1. Application shows an error message that the index given is invalid + + Use case resumes from step 2. + * 3b. The given details are invalid + ** 3b1. Application shows an error message that the details given are invalid + + Use case resumes at step 2. +a|*UC07:* View event details + +*Actor:* Admin + +*Precondition(s):* Admin is logged in + +*Guarantee(s):* + +*MSS:* + + . Admin requests to list all events + . Application displays a list of all events + . Admin requests to view event details at a specific index in the list + . Application displays the details of the event + + Use case ends. + + +*Extensions:* + + * 2a. The event list is empty + ** 2a1. Application shows an error message that event list is empty + + Use case ends. + * 3a. The given index is invalid + ** 3a1. Application shows an error message that the index given is invalid + + Use case resumes from step 2. +a|*UC08:* Delete event details + +*Actor:* Admin + +*Precondition(s):* Admin is logged in + +*Guarantee(s):* + +*MSS:* + + . Admin requests to list all events + . Application displays a list of all events + . Admin requests to delete event details at a specific index in the list + . Application requests for confirmation + . Admin confirms the deletion + . Application deletes the event details + . Application displays a successful deletion message to Admin + + Use case ends. + + +*Extensions:* + + * 2a. The events list is empty + ** 2a1. Application shows an error message that event list is empty + + Use case ends. + * 3a. The given index is invalid + ** 3a1. Application shows an error message that the index given is invalid + + Use case resumes from step 2. +a|*UC09:* Add volunteer hours to volunteer profile + +*Actor:* Admin + +*Precondition(s):* Admin is logged in + +*Guarantee(s):* + +*MSS:* + + . Application [underline]#displays the volunteer profile UC02# + . Admin requests to list all volunteer hours of the volunteer + . Application displays a list of all volunteer hours of the volunteer + . Admin chooses to add volunteer hours + . Application requests for details of the volunteer hours + . Admin enters the requested details + . Application requests for confirmation + . Admin confirms the addition + . Application adds the volunteer hours and notifies Admin of success + + Use case ends. + + +*Extensions:* + + * 2a. The volunteer hours list is empty + ** 2a1. Application shows an error message that volunteer hours list is empty + + Use case ends. + * 8a. Application detects an error in the entered data + ** 8a1. Application requests for the correct data + ** 8a2. Admin enters new data + ** Steps 8a1-8a2 are repeated until the data entered is valid + + Use case resumes from step 9. +a|*UC10:* Edit volunteer hours in volunteer profile + +*Actor:* Admin + +*Precondition(s):* Admin is logged in + +*Guarantee(s):* + +*MSS:* + + . Application [underline]#displays the volunteer profile UC02# + . Admin requests to list all volunteer hours of the volunteer + . Application displays a list of all volunteer hours of the volunteer + . Admin enters the index and the details of the volunteer hours to be changed + . Application updates the volunteer hours and notifies Admin of success + + Use case ends. + + +*Extensions:* + + * 2a. The volunteer hours list is empty + ** 2a1. Application shows an error message that volunteer hours list is empty + + Use case ends. + * 4a. The given index is invalid + ** Application shows an error message that the index given is invalid + + Use case resumes from step 5. + * 4b. The given details are invalid + ** 4b1. Application shows an error message that the details given is invalid + + Use case resumes from step 5. +|======================================================================= -* ... -* ... +[appendix] +== Non Functional Requirements -Cons: +* Reasonable response time (2-3s) +* Backward compatibility by being able to transfer data from older versions of the application when updating each version +* Should work on any <> as long as it has Java `9` or higher installed. +* Files containing volunteer data should be encrypted +* A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. -* ... -* ... +[appendix] +== Glossary +[width="100%",cols="30%,70%",options="header",] +|======================================================================= +| Term| Explanation +| *Admin*| Our application’s intended target user (Most likely the volunteer manager). +| *Application*| Refers to our system. +| *CLI* | Command Line Interface. +| *Context*| A context refers to the management screen that users will see. +| *GUI* | Graphical User Interface. +| *UCXX*| Use case with XX being the use case ID. +|[[mainstream-os]] *Mainstream OS*| Windows, Linux, Unix, OS-X. +| *Volunteer*| A volunteer who has signed up and has a profile with the organization. +| *Volunteer Manager*| Staff working for the organization, who handles administrative issues pertaining to volunteer and event management. +|======================================================================= [appendix] == Instructions for Manual Testing @@ -927,7 +1835,7 @@ Given below are instructions to test the app manually. [NOTE] These instructions only provide a starting point for testers to work on; testers are expected to do more _exploratory_ testing. -=== Launch and Shutdown +=== Launch and shutdown . Initial launch @@ -941,26 +1849,14 @@ These instructions only provide a starting point for testers to work on; testers .. Re-launch the app by double-clicking the jar file. + Expected: The most recent window size and location is retained. -_{ more test cases ... }_ - -=== Deleting a person +=== Deleting a volunteer -. Deleting a person while all persons are listed +. Deleting a volunteer while all persons are listed .. Prerequisites: List all persons using the `list` command. Multiple persons in the list. .. Test case: `delete 1` + Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. .. Test case: `delete 0` + - Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. + Expected: No volunteer is deleted. Error details shown in the status message. Status bar remains the same. .. Other incorrect delete commands to try: `delete`, `delete x` (where x is larger than the list size) _{give more}_ + Expected: Similar to previous. - -_{ more test cases ... }_ - -=== Saving data - -. Dealing with missing/corrupted data files - -.. _{explain how to simulate a missing/corrupted file and the expected behavior}_ - -_{ more test cases ... }_ diff --git a/docs/LearningOutcomes.adoc b/docs/LearningOutcomes.adoc deleted file mode 100644 index 83cda0927226..000000000000 --- a/docs/LearningOutcomes.adoc +++ /dev/null @@ -1,266 +0,0 @@ -= Learning Outcomes -:site-section: LearningOutcomes -:toc: macro -:toc-title: -:toclevels: 1 -:sectnums: -:sectnumlevels: 1 -:imagesDir: images -:stylesDir: stylesheets -:repoURL: https://github.com/se-edu/addressbook-level4/tree/master - -After studying this code and completing the corresponding exercises, you should be able to, - -toc::[] - -''' - -== Use High-Level Designs `[LO-HighLevelDesign]` - -Note how the <> describes the high-level design using an _Architecture Diagrams_ and high-level sequence diagrams. - -*Resources* - -* https://se-edu.github.io/se-book/architecture/[se-edu/se-book: Design: Architecture] -* https://se-edu.github.io/se-book/design/introduction/multilevelDesign/[se-edu/se-book: Design: Introduction: Multi-Level Design] - -''' - -== Use Event-Driven Programming `[LO-EventDriven]` - -Note how the <> uses events to communicate with components without needing a direct coupling. Also note how the link:{repoURL}/src/main/java/seedu/address/commons/core/index/EventsCenter.java[`EventsCenter.java`] acts as an event dispatcher to facilitate communication between event creators and event consumers. - -*Resources* - -* https://se-edu.github.io/se-book/architecture/architecturalStyles/eventDriven/[se-edu/se-book: Design: Architecture: Architecture Styles: Event-Driven Architectural Style] - -''' - -== Use API Design `[LO-ApiDesign]` - -Note how components of AddressBook have well-defined APIs. For example, the API of the `Logic` component is given in the link:{repoURL}/src/main/java/seedu/address/logic/Logic.java[`Logic.java`] -image:LogicClassDiagram.png[width="800"] - -*Resources* - -* https://se-edu.github.io/se-book/reuse/apis/[se-edu/se-book: Implementation: Reuse: APIs] - -''' - -== Use Assertions `[LO-Assertions]` - -Note how the AddressBook app uses Java ``assert``s to verify assumptions. - -*Resources* - -* https://se-edu.github.io/se-book/errorHandling/assertions/[se-edu/se-book: Implementation: Error Handling: Assertions] - -=== Exercise: Add more assertions - -* Make sure assertions are enabled in your IDE by forcing an assertion failure (e.g. add `assert false;` somewhere in the code and run the code to ensure the runtime reports an assertion failure). -* Add more assertions to AddressBook as you see fit. - - -''' - -== Use Logging `[LO-Logging]` - -Note <>. - -*Resources* - -* https://se-edu.github.io/se-book/errorHandling/logging/[se-edu/se-book: Implementation: Error Handling: Logging] - -=== Exercise: Add more logging - -Add more logging to AddressBook as you see fit. - - -''' - -== Use Defensive Coding `[LO-DefensiveCoding]` - -Note how AddressBook uses the `ReadOnly*` interfaces to prevent objects being modified by clients who are not supposed to modify them. - -*Resources* - -* https://se-edu.github.io/se-book/errorHandling/defensiveProgramming/[se-edu/se-book: Implementation: Error Handling: Defensive Programming] - -=== Exercise: identify more places for defensive coding - -Analyze the AddressBook code/design to identify, - -* where defensive coding is used -* where the code can be more defensive - -''' - -== Use Build Automation `[LO-BuildAutomation]` - -Note <>. - -*Resources* - -* https://se-edu.github.io/se-book/integration/buildAutomation/what/[se-edu/se-book: Implementation: Integration: Build Automation: What] - -=== Exercise: Use gradle to run tasks - -* Use gradle to do these tasks: Run all tests in headless mode, build the jar file. - -=== Exercise: Use gradle to manage dependencies - -* Note how the build script `build.gradle` file manages third party dependencies such as ControlsFx. Update that file to manage a third-party library dependency. - - -''' - -== Use Continuous Integration `[LO-ContinuousIntegration]` - -Note <>. (https://travis-ci.org/se-edu/addressbook-level4[image:https://travis-ci.org/se-edu/addressbook-level4.svg?branch=master[Build Status]]) - -*Resources* - -* https://se-edu.github.io/se-book/integration/buildAutomation/continuousIntegrationDeployment/[se-edu/se-book: Implementation: Integration: Build Automation: CI & CD] - -=== Exercise: Use Travis in your own project - -* Set up Travis to perform CI on your own fork. - - -''' - -== Use Code Coverage `[LO-CodeCoverage]` - -Note how our CI server <>. (https://coveralls.io/github/se-edu/addressbook-level4?branch=master[image:https://coveralls.io/repos/github/se-edu/addressbook-level4/badge.svg?branch=master[Coverage Status]]) After <> for your project, you can visit Coveralls website to find details about the coverage of code pushed to your repo. https://coveralls.io/github/se-edu/addressbook-level4?branch=master[Here] is an example. - -*Resources* - -* https://se-edu.github.io/se-book/testing/testCoverage/[se-edu/se-book: QA: Testing: Test Coverage] - -=== Exercise: Use the IDE to measure coverage locally - -* Use the IDE to measure code coverage of your tests. - -''' - -== Apply Test Case Design Heuristics `[LO-TestCaseDesignHeuristics]` - -The link:{repoURL}/src/test/java/seedu/address/commons/util/StringUtilTest.java[`StringUtilTest.java`] -class gives some examples of how to use _Equivalence Partitions_, _Boundary Value Analysis_, and _Test Input Combination Heuristics_ to improve the efficiency and effectiveness of test cases testing the link:../src/main/java/seedu/address/commons/util/StringUtil.java[`StringUtil.java`] class. - -*Resources* - -* https://se-edu.github.io/se-book/testCaseDesign/[se-edu/se-book: QA: Test Case Design] - -=== Exercise: Apply Test Case Design Heuristics to other places - -* Use the test case design heuristics mentioned above to improve test cases in other places. - -''' - -== Write Integration Tests `[LO-IntegrationTests]` - -Consider the link:{repoURL}/src/test/java/seedu/address/storage/StorageManagerTest.java[`StorageManagerTest.java`] class. - -* Test methods `prefsReadSave()` and `addressBookReadSave()` are integration tests. Note how they simply test if The `StorageManager` class is correctly wired to its dependencies. -* Test method `handleAddressBookChangedEvent_exceptionThrown_eventRaised()` is a unit test because it uses _dependency injection_ to isolate the SUT `StorageManager#handleAddressBookChangedEvent(...)` from its dependencies. - -Compare the above with link:{repoURL}/src/test/java/seedu/address/logic/LogicManagerTest.java[`LogicManagerTest`]. Some of the tests in that class (e.g. `execute_*` methods) are neither integration nor unit tests. They are _integration + unit_ tests because they not only check if the LogicManager is correctly wired to its dependencies, but also checks the working of its dependencies. For example, the following two lines test the `LogicManager` but also the `Parser`. - -[source,java] ----- -@Test -public void execute_invalidCommandFormat_throwsParseException() { - ... - assertParseException(invalidCommand, MESSAGE_UNKNOWN_COMMAND); - assertHistoryCorrect(invalidCommand); -} ----- - -*Resources* - -* https://se-edu.github.io/se-book/testing/testingTypes/[se-edu/se-book: QA: Testing: Testing Types] - -=== Exercise: Write unit and integration tests for the same method. - -* Write a unit test for a high-level method somewhere in the code base (or a new method you wrote). -* Write an integration test for the same method. - -''' - -== Write System Tests `[LO-SystemTesting]` - -Note how tests below `src/test/java/systemtests` package (e.g link:{repoURL}/src/test/java/systemtests/AddCommandSystemTest.java[`AddCommandSystemTest.java`]) are system tests because they test the entire system end-to-end. - -*Resources* - -* https://se-edu.github.io/se-book/testing/testingTypes/[se-edu/se-book: QA: Testing: Testing Types] - -=== Exercise: Write more system tests - -* Write system tests for the new features you add. - -''' - -== Automate GUI Testing `[LO-AutomateGuiTesting]` - -Note how this project uses TextFX library to automate GUI testing, including <>. - -=== Exercise: Write more automated GUI tests - -* Covered by `[LO-SystemTesting]` - -''' - -== Apply Design Patterns `[LO-DesignPatterns]` - -Here are some example design patterns used in the code base. - -* *Singleton Pattern* : link:{repoURL}/src/main/java/seedu/address/commons/core/EventsCenter.java[`EventsCenter.java`] is Singleton class. Its single instance can be accessed using the `EventsCenter.getInstance()` method. -* *Facade Pattern* : link:{repoURL}/src/main/java/seedu/address/storage/StorageManager.java[`StorageManager.java`] is not only shielding the internals of the Storage component from outsiders, it is mostly redirecting method calls to its internal components (i.e. minimal logic in the class itself). Therefore, `StorageManager` can be considered a Facade class. -* *Command Pattern* : The link:{repoURL}/src/main/java/seedu/address/logic/commands/Command.java[`Command.java`] and its sub classes implement the Command Pattern. -* *Observer Pattern* : The <> used by this code base employs the Observer pattern. For example, objects that are interested in events need to have the `@Subscribe` annotation in the class (this is similar to implementing an `\<>` interface) and register with the `EventsCenter`. When something noteworthy happens, an event is raised and the `EventsCenter` notifies all relevant subscribers. Unlike in the Observer pattern in which the `\<>` class is notifying all `\<>` objects, here the `\<>` classes simply raises an event and the `EventsCenter` takes care of the notifications. -* *MVC Pattern* : -** The 'View' part of the application is mostly in the `.fxml` files in the `src/main/resources/view` folder. -** `Model` component contains the 'Model'. However, note that it is possible to view the `Logic` as the model because it hides the `Model` behind it and the view has to go through the `Logic` to access the `Model`. -** Sub classes of link:{repoURL}/src/main/java/seedu/address/ui/UiPart.java[`UiPart`] (e.g. `PersonListPanel` ) act as 'Controllers', each controlling some part of the UI and communicating with the 'Model' (via the `Logic` component which sits between the 'Controller' and the 'Model'). -* *Abstraction Occurrence Pattern* : Not currently used in the app. - -*Resources* - -* https://se-edu.github.io/se-book/designPatterns/[se-edu/se-book: Design: Design Patterns] - -=== Exercise: Discover other possible applications of the patterns - -* Find other possible applications of the patterns to improve the current design. e.g. where else in the design can you apply the Singleton pattern? -* Discuss pros and cons of applying the pattern in each of the situations you found in the previous step. - -=== Exercise: Find more applicable patterns - -* Learn other _Gang of Four_ Design patterns to see if they are applicable to the app. - -''' - -== Use Static Analysis `[LO-StaticAnalysis]` - -Note how this project uses the http://checkstyle.sourceforge.net/[CheckStyle] static analysis tool to confirm compliance with the coding standard. - -*Resources* - -* https://se-edu.github.io/se-book/qualityAssurance/staticAnalysis/[se-edu/se-book: QA: Static Analysis] - -=== Exercise: Use CheckStyle locally to check style compliance - -* Install the CheckStyle plugin for your IDE and use it to check compliance of your code with our style rules (given in `/config/checkstyle/checkstyle.xml`). - -''' - -== Do Code Reviews `[LO-CodeReview]` - -* Note how some PRs in this project have been reviewed by other developers. Here is an https://github.com/se-edu/addressbook-level4/pull/147[example]. -* Also note how we have used https://www.codacy.com[Codacy] to do automate some part of the code review workload (https://www.codacy.com/app/damith/addressbook-level4?utm_source=github.com&utm_medium=referral&utm_content=se-edu/addressbook-level4&utm_campaign=Badge_Grade[image:https://api.codacy.com/project/badge/Grade/fc0b7775cf7f4fdeaf08776f3d8e364a[Codacy Badge]]) - - -=== Exercise: Review a PR - -* Review PRs created by team members. diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index 7e0070e12f49..6afef0a5eecf 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -1,8 +1,9 @@ -= AddressBook Level 4 - User Guide += SocialCare - User Guide :site-section: UserGuide :toc: :toc-title: :toc-placement: preamble +:toclevels: 4 :sectnums: :imagesDir: images :stylesDir: stylesheets @@ -12,151 +13,101 @@ ifdef::env-github[] :tip-caption: :bulb: :note-caption: :information_source: endif::[] -:repoURL: https://github.com/se-edu/addressbook-level4 +:repoURL: https://github.com/CS2103-AY1819S1-W16-2/main -By: `Team SE-EDU` Since: `Jun 2016` Licence: `MIT` +By: `Team W16-2` Since: `Sept 2018` Licence: `MIT` == Introduction -AddressBook Level 4 (AB4) is for those who *prefer to use a desktop app for managing contacts*. More importantly, AB4 is *optimized for those who prefer to work with a Command Line Interface* (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB4 can get your contact management tasks done faster than traditional GUI apps. Interested? Jump to the <> to get started. Enjoy! +Non-profit organizations rely on volunteer work to maintain parts of their operations. A volunteer management system is +essential in helping to retain volunteers by ensuring that there is a large enough pool of volunteers who are motivated +to support the various events. Therefore, it is critical that a organization is able +to source the right person for the right activity. -== Quick Start - -. Ensure you have Java version `9` or later installed in your Computer. -. Download the latest `addressbook.jar` link:{repoURL}/releases[here]. -. Copy the file to the folder you want to use as the home folder for your Address Book. -. Double-click the file to start the app. The GUI should appear in a few seconds. -+ -image::Ui.png[width="790"] -+ -. Type the command in the command box and press kbd:[Enter] to execute it. + -e.g. typing *`help`* and pressing kbd:[Enter] will open the help window. -. Some example commands you can try: - -* *`list`* : lists all contacts -* **`add`**`n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : adds a contact named `John Doe` to the Address Book. -* **`delete`**`3` : deletes the 3rd contact shown in the current list -* *`exit`* : exits the app - -. Refer to <> for details of each command. - -[[Features]] -== Features +SocialCare is an application that is designed to help your organization manage your volunteers effectively. +You will be able to: -==== -*Command Format* +* Manage volunteer information such as contact details. +* Manage events for your organization. +* Create volunteering records for your volunteers. -* Words in `UPPER_CASE` are the parameters to be supplied by the user e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`. -* Items in square brackets are optional e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`. -* Items with `…`​ after them can be used multiple times including zero times e.g. `[t/TAG]...` can be used as `{nbsp}` (i.e. 0 times), `t/friend`, `t/friend t/family` etc. -* Parameters can be in any order e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. -==== +Interested? Jump to <> to get started. -=== Viewing help : `help` +Enjoy! -Format: `help` - -=== Adding a person: `add` - -Adds a person to the address book + -Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` +// tag::quick-start[] +== Quick Start +This section contains information on how you can run SocialCare on your desktop. -[TIP] -A person can have any number of tags (including 0) +To begin, follow the steps below: -Examples: +. Check that you have Java version `9` or later installed in your Computer. +. Download the latest `socialcare.jar` link:{repoURL}/releases[here]. +. Copy the file to the folder you want to use as the home folder for SocialCare. +. Double-click the file to start the app. The Graphical User Interface (GUI) should appear in a few seconds. -* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` -* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal` +.A labelled screenshot of the parts of the application +image::UiLabelled.png[width="790"] -=== Listing all persons : `list` +The figure above shows the typical arrangement of the parts of the application. It is currently showing the screen that +users will see upon startup. -Shows a list of all persons in the address book. + -Format: `list` +1. _Toolbar_: Provides quick access to exit the application or to open the user guide. -=== Editing a person : `edit` +2. _Panel_: Displays volunteers or events, depending on which item you are managing. -Edits an existing person in the address book. + -Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]...` +3. _Display Box_: Shows more information for the selected item from the panel. -**** -* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index *must be a positive integer* 1, 2, 3, ... -* At least one of the optional fields must be provided. -* Existing values will be updated to the input values. -* When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative. -* You can remove all the person's tags by typing `t/` without specifying any tags after it. -**** +4. _Command Box_: Allows you to input commands for execution. -Examples: +5. _Command Result Box_: Displays status of executed commands. -* `edit 1 p/91234567 e/johndoe@example.com` + -Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively. -* `edit 2 n/Betsy Crower t/` + -Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags. +6. _Status Bar_: Provides further information of application. -=== Locating persons by name: `find` -Finds persons whose names contain any of the given keywords. + -Format: `find KEYWORD [MORE_KEYWORDS]` +To ensure that everything is running, you can try entering commands into the command box and press kbd:[Enter] to execute them. + +e.g. typing *`help`* and pressing kbd:[Enter] will open the help window. -**** -* The search is case insensitive. e.g `hans` will match `Hans` -* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans` -* Only the name is searched. -* Only full words will be matched e.g. `Han` will not match `Hans` -* Persons matching at least one keyword will be returned (i.e. `OR` search). e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang` -**** -Examples: +[NOTE] +SocialCare allows you to manage both volunteers and events. The panel will update to show the relevant items. See +<> for more details. -* `find John` + -Returns `john` and `John Doe` -* `find Betsy Tim John` + -Returns any person having names `Betsy`, `Tim`, or `John` +You can refer to <> for details of each command. -=== Deleting a person : `delete` +//end::quick-start[] -Deletes the specified person from the address book. + -Format: `delete INDEX` +[[Features]] +== Features -**** -* Deletes the person at the specified `INDEX`. -* The index refers to the index number shown in the displayed person list. -* The index *must be a positive integer* 1, 2, 3, ... -**** +==== +*Command Format* -Examples: +* Words in `UPPER_CASE` are the parameters to be supplied by the user e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`. +* Items in square brackets are optional e.g `[n/NAME]`. +* Items with `…`​ after them can be used multiple times including zero times e.g. `[t/TAG]...` can be used as `{nbsp}` (i.e. 0 times), `t/charity`, `t/charity t/help` etc. +* Parameters can be in any order e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. +==== -* `list` + -`delete 2` + -Deletes the 2nd person in the address book. -* `find Betsy` + -`delete 1` + -Deletes the 1st person in the results of the `find` command. +=== General Commands -=== Selecting a person : `select` +[[command-help]] +==== Viewing help : `help` -Selects the person identified by the index number used in the displayed person list. + -Format: `select INDEX` +Opens a new window which shows the user guide. -**** -* Selects the person and loads the Google search page 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, ...` -**** +Format: `help` -Examples: +Example(s): -* `list` + -`select 2` + -Selects the 2nd person in the address book. -* `find Betsy` + -`select 1` + -Selects the 1st person in the results of the `find` command. +* `help` + +A new window appears which displays the user guide. -=== Listing entered commands : `history` +[[command-history]] +==== Listing entered commands : `history` Lists all the commands that you have entered in reverse chronological order. + + Format: `history` [NOTE] @@ -164,18 +115,25 @@ Format: `history` Pressing the kbd:[↑] and kbd:[↓] arrows will display the previous and next input respectively in the command box. ==== -// tag::undoredo[] -=== Undoing previous command : `undo` +Example(s): + +* `history` + +The command result box will display the commands that you have entered in reverse chronological order. + +// tag::undoreo[] +[[command-undo]] +==== Undoing previous command : `undo` + +Restores the system to the state before the previous _undoable_ command was executed. + -Restores the address book to the state before the previous _undoable_ command was executed. + Format: `undo` [NOTE] ==== -Undoable commands: those commands that modify the address book's content (`add`, `delete`, `edit` and `clear`). +Undoable commands: those commands that modify the system's content (`add`, `edit`, and `delete`). ==== -Examples: +Example(s): * `delete 1` + `list` + @@ -191,12 +149,14 @@ The `undo` command fails as there are no undoable commands executed previously. `undo` (reverses the `clear` command) + `undo` (reverses the `delete 1` command) + -=== Redoing the previously undone command : `redo` +[[command-redo]] +==== Redoing the previously undone command : `redo` Reverses the most recent `undo` command. + + Format: `redo` -Examples: +Example(s): * `delete 1` + `undo` (reverses the `delete 1` command) + @@ -214,47 +174,591 @@ The `redo` command fails as there are no `undo` commands executed previously. `redo` (reapplies the `clear` command) + // end::undoredo[] -=== Clearing all entries : `clear` +// tag::command-clear[] +[[command-clear]] +==== Clearing all entries : `clear` + +Clears all data from the application. -Clears all entries from the address book. + Format: `clear` -=== Exiting the program : `exit` +Example(s): + +* `clear` + +Resets the application to a clean state. The panel is also updated to reflect the changes. + + +.Before clearing entries +image::command_clear_before.png[clear bef, 600] + +.After clearing entries +image::command_clear_after.png[clear aft, 600] + +The figures above shows the before and after state of clearing the entries of the application. +//end::command-clear[] + +[[command-exit]] +==== Exiting the application : `exit` + +Exits the application. + -Exits the program. + Format: `exit` -=== Saving the data +Example(s): + +* `exit` + +Exits from the application and return to the user's desktop. + +// tag::command-switch[] +[[command-switch]] +==== Switching panels: `switch` + +Switches the panel to display either volunteers or events + + +Format: `switch -CONTEXT_ID` + +**** +* The application will always display the 'volunteer' panel upon startup. +* This command allows you to switch the panel between two distinct entities: 'volunteers' and 'events'. +* CONTEXT_ID for events is 'e'. +* CONTEXT_ID for volunteers is 'v'. +**** + +Example(s): + +* `switch -e` + +Updates the panel displaying the list of volunteers to display the list of events. + +The following figure shows the expected panel before and after entering the `switch` command. + +.Panel display changing from list of volunteers to list of events +image::command_switch.png[switch, 500] +//end::command-switch[] + +[[command-overview]] +==== Viewing overview: `overview` + +Display box displays statistical overview of volunteers and events, such as number of events and volunteer distribution. + + +Format: `overview` + +[NOTE] +This command only works when managing volunteers or events. The command does not work when manging volunteering records. + +Example(s): + +* `overview` + +Display box displays statistics of number of types of events and volunteer distribution. + +The following figure shows the expected display after executing the `overview` command. + +.Overview of events and volunteers +image::command_overview.png[overview, 600] + +// tag::volunteermanagement[] +=== Volunteer Management + +[[command-volunteer-add]] +==== Registering new volunteer: `add` + +Adds a volunteer to the system when in the volunteers context + +Format: `add n/NAME g/GENDER b/BIRTHDAY p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` + +**** +* Birthday is in the 'DD-MM-YYYY format'. +* VolunteerId (NRIC) can be in either lowercase or uppercase. +* A volunteer can have any number of tags (including 0). +**** + +Example(s): + +.Before adding a volunteer +image::command_volunteer_list.png[add command, 200] + +The figure above shows how the panel looks like before executing the commands below. + +* `add n/John Doe ic/S9531080R g/m b/05-08-1995 p/87183749 e/John@gmail.com a/Yishun Block 62 ` ++ +Adds a volunteer with the following properties: ++ +[options="header", cols="1,3"] +|=== +|Property |Value +|Name |John Doe +|NRIC |S9531080R +|Gender |m (Male) +|Birthday |05-08-1995 +|Phone |87183749 +|Email |John@gmail.com +|Address |Yishun Block 62 +|=== +.Output of `add` +image::command_volunteer_add_after1.png[add command, 500] + + +* `add n/Betty Sue ic/S9567432B g/f b/31-12-1995 p/81749272 e/Betty@gmail.com a/Ang Mo Kio Block 62 t/Longtime t/Helpful` ++ +Adds a volunteer with the following properties: ++ +[options="header", cols="1,3"] +|=== +|Property |Value +|Name |Betty Sue +|NRIC |S9567432B +|Gender |f (Female) +|Birthday |31-12-1995 +|Phone |81749272 +|Email |Betty@gmail.com +|Address |Ang Mo Kio Block 62 +|Tags |Longtime, Helpful +|=== +.Output of `add` +image::command_volunteer_add_after2.png[add command, 500] + +[[command-volunteer-list]] +==== Listing all volunteers : `list` + +Lists all volunteers in the system when in the volunteers context. + +Format: `list` + +The figure below shows the expected panel after executing the `list` command. + +.Output of `list` +image::command_volunteer_list.png[list command, 200] + + +[[command-volunteer-edit]] +==== Editing volunteers details : `edit` + +Edit details of an existing volunteer in the system when in the volunteers context. + +Format: `edit VOLUNTEER_INDEX [n/NAME] [g/GENDER] [b/BIRTHDAY] [p/PHONE_NUMBER] [a/ADDRESS] [e/EMAIL] [a/ADDRESS] [t/TAG]...` + +**** +* Edits the volunteer at the specified `INDEX`. The index refers to the index number shown in the displayed volunteer list. The index *must be a positive integer* 1, 2, 3, ... +* At least one of the optional fields must be provided. +* Editing of VolunteerId (NRIC) is not allowed. +* Existing values will be updated to the input values. +* When editing tags, the existing tags of the volunteer will be removed i.e adding of tags is not cumulative. +* You can remove all the volunteer's tags by typing `t/` without specifying any tags after it. +**** + +Example(s): + +* `edit 1 n/John Doe` + +Edits the name of the volunteer at index 1 + +The figures below show the before and after results of an edit command. + +-- +.The targeted volunteer is updated to reflect the new values after entering the edit command +image::command_volunteer_edit.png[After edit, 500] +-- + + +[[command-volunteer-delete]] +==== Deleting volunteer details : `delete` + +Deletes details of an existing volunteer in the system when in the volunteer context. + +Format: `delete VOLUNTEER_INDEX` + +Example(s): + +* `delete 1` + +Deletes the details of the volunteer specified at index 1 + +The figures below show the before and after results of a delete command. + +-- +.The targeted volunteer at index 1 is deleted after entering the delete command +image::command_volunteer_delete.png[After delete, 500] +-- + +// end::volunteermanagement[] + +// tag::exportcert[] +// tag::exportcert-sharan-ppp[] +[[command-volunteer-exportcert]] +==== Exporting volunteer certificate : `exportcert` + +Exports a PDF document to the user's current working directory detailing a volunteer's involvement with the organisation. This document includes: + +* Title: 'Certificate of Recognition' +* Date of export +* Volunteer name +* Volunteer NRIC +* List of events involved in - Event name, event ID, hours contributed, event start date and event end date +* Total hours contributed across all events + +Format: `exportcert VOLUNTEER_INDEX` + +* Exports a PDF certificate for the volunteer at the specified `VOLUNTEER INDEX` +* `VOLUNTEER INDEX` **must be a positive integer** 1, 2, 3, ... +* If the index given exceeds the number of volunteers in the displayed volunteer list, the message 'The volunteer index provided is invalid.' will be shown. + +[NOTE] +==== +A certificate will be exported only if *the volunteer has event records* and *at least 1 record has a positive, non-zero hour value*. +==== + +Example: + +* `exportcert 1` + +Exports a PDF certificate for the volunteer at index 1 to the user's current working directory. +A success message will also be displayed in the following form: 'Certificate exported for volunteer at INDEX 1 to '. + +[NOTE] +==== +*Where will my files be exported to?* + +If SocialCare has the permission to create folders on your machine, the certificates will be exported to a folder named 'Certs'. Else, they can be found next to the .jar file used to run the application. +==== + +Here is what the exported certificate will look like: (Note that the number within the square brackets [ ] following the event name corresponds to the event ID) + +.Sample exported volunteer certificate +[.thumb] +image::CurrentVolunteerCert.png[width="450"] + +An empty line is provided at the end of the certificate for manual signing off. Feel free to add a signature or an organizational stamp to add credibility to the certificate! + +[NOTE] +==== +To avoid exported file name clashes for volunteers with the same name, we have appended the volunteer's NRIC to the filename as well. Exported file names will have the format '_.pdf' (E.g. John Doe_S8512345A.pdf) +==== +// end::exportcert-sharan-ppp[] + +You can refer to the following flowchart to better understand the feedback messages displayed by the application, and derive what your subsequent actions should be. (E.g. If you get the message "The volunteer index provided is invalid.", then try replacing the you had input.) + +.`exportcert` command flowchart +[.thumb] +image::command_exportcert_ad.png[width="500"] +// end::exportcert[] + +// tag::eventmanagement[] +=== Event Management + +The following commands can only be accessed after switching to the 'event' panel. (see <>) + +[[command-event-add]] +==== Adding new event: `add` + +Adds an event to the system. + + +Format: `add n/NAME l/LOCATION sd/START_DATE ed/END_DATE st/START_TIME et/END_TIME d/DESCRIPTION [t/TAG]...` + +**** +* Start date and end date must be in 'DD-MM-YYYY format'. +* Start time and end time must be in 'HH:MM format'. +* An event can have any number of tags (including 0). +**** + +Example(s): + +The figure below shows how the panel looks like before executing the example(s) below. + +.Panel before adding an event +image::command_event_add_before.png[add command, 200] + + +* `add n/Flag Day l/Yishun MRT sd/31-10-2018 ed/31-10-2018 st/09:00 et/15:00 d/For the children's home` + ++ +Adds an event with the properties specified in the command above. The expected result is shown in the figure below. ++ +.Result of `add n/Flag Day l/Yishun MRT sd/31-10-2018 ed/31-10-2018 st/09:00 et/15:00 d/For the children's home` +image::command_event_add_before_after1.png[add command, 500] + +* `add n/Fundraising l/Tampines Street 31 sd/15-11-2018 ed/17-11-2018 st/13:00 et/18:00 d/Raising funds t/fundraiser +t/charity` ++ +Adds an event with the properties specified in the command above. The expected result is shown in the figure below. ++ +.Result of `add n/Fundraising l/Tampines Street 31 sd/15-11-2018 ed/17-11-2018 st/13:00 et/18:00 d/Raising funds t/fundraiser t/charity` +image::command_event_add_before_after2.png[add command, 500] + + +[[command-event-list]] +==== Listing all events : `list` -Address book data are saved in the hard disk automatically after any command that changes the data. + +Lists all events in the system and display them in the panel. + + +Format: `list` + +Displays all existing events in the system in the panel. + +The figure below shows a panel displaying all existing events after executing the `list` command. + +.Output of `list` +image::command_event_list.png[list command, 200] + +[[command-event-edit]] +==== Editing event details : `edit` + +Edit details of an existing event in the system when in the 'event' context. + + +Format: `edit EVENT_INDEX [n/NAME] [l/LOCATION] [sd/START_DATE] [ed/END_DATE] [st/START_TIME] [et/END_TIME] [d/DESCRIPTION] [t/TAG]...` + +**** +* Edits the event at the specified `EVENT_INDEX`. The index refers to the index number shown in the displayed event list. The index *must be a positive integer* 1, 2, 3, ... +* At least one of the optional fields must be provided. +* Existing values will be updated to the input values. +* When editing tags, the existing tags of the event will be removed i.e adding of tags is not cumulative. +* You can remove all the event's tags by typing `t/` without specifying any tags after it. +**** + +Example(s): + +The figure below indicates the EVENT_INDEX and shows how the panel looks like before executing the example(s) below. + +.Panel before editing an event, EVENT_INDEX is indicated in the circles +image::command_event_edit_before.png[add command, 200] + +* `edit 1 n/Charity Fun Run t/` + +Edits the name of event at index 1 and removes all tags. +The expected result is shown in the figure below. ++ +.Result of `edit 1 n/Charity Fun Run t/` +image::command_event_edit_before_after.png[Before edit, 500] + + +[[command-event-delete]] +==== Deleting event: `delete` + +Deletes an existing event in the system when in the 'event' context. + + +Format: `delete EVENT_INDEX` + +Example(s): + +The figure below indicates the EVENT_INDEX and shows how the panel looks like before executing the example(s) below. + +.Panel before deleting an event, EVENT_INDEX is indicated in the circles +image::command_event_delete_before.png[add command, 200] + +* `delete 3` + +Deletes the event specified at index 3. +The expected result is shown in the figure below. ++ +.Result of `delete 3` +image::command_event_delete_before_after.png[Before delete, 500] + + +// end::eventmanagement[] + +=== Record Management + +This section contains commands related to managing a volunteering record. + + +**** +* The `manage` command can only be accessed after switching to the 'event' panel. (see <>) + +* The other commands under this section can only be accessed after executing the `manage` command. +**** + +// tag::command-record[] +[[command-record-manage]] +==== Viewing event's volunteer records: `manage` + +The panel updates to show the list of volunteers while the display area shows the volunteers currently registered for the selected event. + + +Format: `manage EVENT_INDEX` + +Example(s): + +* `switch -e` (panel updates to show list of events) + +`manage 1` (view the list of volunteers assigned to the event at index 1) + +See the figures below for a step-by-step guide. + +.Execute `switch -e` +image::command_switch.png[switch execution, 500] + +.`manage 1` targets the event at index 1 +image::command_record_manage_eventIndex.png[switch execution, 200] + +.Labelled screenshot of what to expect after executing `manage 1` +image::command_manage_view.png[manage, 600] + +Refer to the labelled sections in the figure above for the following changes: + +. The panel displays the list of volunteers that you can assign to an event. +. Name of the event being managed and total number of volunteers assigned to it. +. The list of volunteers currently assigned to the event. It will be empty if there are no volunteers assigned. + +//end::command-record[] +[[command-record-add]] +==== Adding volunteer to event: `add` + +Adds a volunteer to the event that is currently being managed. + +Refer to <> on how to manage events. + +Format: `add VOLUNTEER_INDEX [h/HOURS] [r/REMARKS]` + +**** +* VOLUNTEER_INDEX comes from the list of all volunteers shown in the panel. +* Default value for HOURS is '0'. +* Default value for REMARKS is '-'. +**** + +Example(s): + +[NOTE] +The following examples are entered after executing the following commands: + +1. `switch -e` (update panel to display events) + +2. `manage 1` (manage the event at index 1 in the panel. See figure below for expected screen) + +.After executing `manage 1` +image::command_record_add.png[add command, 600] + +* `add 1` + +Adds a volunteer at index 1 to the event with 0 hours. + +Expected display box is shown in the figure below. + +.Output of `add 1` +image::command_record_add_after1.png[add command, 600] + +* `add 1 h/5 r/Driver` + +Adds a volunteer at index 1 to the event with 5 hours and remarks of 'Driver'. + +Expected display box is shown in the figure below. + +.Output of `add 1 h/5 r/Driver` +image::command_record_add_after2.png[add command, 600] + + +[[command-record-edit]] +==== Updating volunteer record: `edit` + +Updates a volunteer record in the event that is currently being managed. + +Refer to <> on how to manage events. + +Format: `edit VOLUNTEER_INDEX h/HOURS [r/REMARKS]` + +**** +* VOLUNTEER_INDEX comes from the volunteers currently registered for the event. +* Just entering `r/` will save the remarks with the default value of '-'. +**** + +The figure below shows the highlighted column that indicates the VOLUNTEER_INDEX that you have to enter. + +This display can be seen after executing the `manage` command. + +.Display after excuting `manage` +image::command_record_edit_volunteerIndex.png[volunteer index, 600] + + +Example(s): + +* `edit 2 h/5 r/Emcee` + +Updates amount of hours volunteered for volunteer at index 3 to 5 hours with remarks of 'Emcee'. + +The figures below show the display box before and after editing a record. + +.Before updating the volunteer record +image::command_record_edit.png[edit command, 600] + +.Output of `edit 2 h/5 r/Emcee` +image::command_record_edit_after.png[edit command, 600] + + + +[[command-record-delete]] +==== Deleting volunteer record from event: `delete` + +Deletes the volunteer record from the event that is currently being managed. + +Refer to <> on how to manage events. + +Format: `delete VOLUNTEER_INDEX` + +[NOTE] +VOLUNTEER_INDEX comes from the table view of existing volunteers. + + +The figure below shows the highlighted column that indicates the VOLUNTEER_INDEX that you have to enter. + +This display can be seen after executing the `manage` command. + +.The VOLUNTEER_INDEX +image::command_record_edit_volunteerIndex.png[volunteer index, 600] + +Example(s): + +* `delete 1` + +Deletes the volunteer record at index 1. + +The figures below show the display box before and after deleting a record. + +.Before deleting the volunteer record +image::command_record_edit.png[delete command, 600] + +.Output of `delete 1` +image::command_record_delete.png[delete command, 600] + + + +=== Miscellaneous + +==== Saving data + +SocialCare data are saved in the hard disk automatically after any command that changes the data. + There is no need to save manually. // tag::dataencryption[] -=== Encrypting data files `[coming in v2.0]` +==== Encrypting data files `[coming in v2.0]` -_{explain how the user can enable/disable data encryption}_ // end::dataencryption[] +== Commands Summary + +This section contains a summary of the commands available. + +=== General Commands + +[width="100%",cols="10%, 30%, 30%, 30%",options="header",] +|======================================================================= +| Command | Format | Example | Section Link +| *Clear* | `clear` | `clear` | <> +| *Help* | `help` | `help` | <> +| *History* | `history` | `history` | <> +| *Overview* | `overview` | `overview` | <> +| *Redo* | `redo` | `redo` | <> +| *Switch* | `switch -[CONTEXT_ID]` | `switch -e` | <> +| *Undo* | `undo` | `undo` | <> +|======================================================================= + +=== Volunteer Management + +[width="100%",cols="10%, 30%, 30%, 30%",options="header",] +|======================================================================= +| Command | Format | Example | Section Link +| *Add* | `add n/NAME ic/NRIC g/GENDER b/BIRTHDAY p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` | `add n/John Doe ic/S1234567A g/m b/05-08-1995 p/87183749 e/John@gmail.com a/Yishun Block 62`| <> +| *Delete* | `delete VOLUNTEER_INDEX` | `delete 3` | <> +| *Edit* | `edit VOLUNTEER_INDEX [n/NAME][b/BIRTHDAY] [g/GENDER] [a/ADDRESS] [e/EMAIL] [p/PHONE_NUMBER] [t/TAG]...` | `edit 2 n/James Lee e/jameslee@example.com` | <> +| *Export Certificate* | `exportcert VOLUNTEER_INDEX` | `exportcert 2` | <> +| *List* | `list` | `list` | <> +|======================================================================= + +=== Event Management + +[width="100%",cols="10%, 30%, 30%, 30%",options="header",] +|======================================================================= +| Command | Format | Example | Section Link +| *Add* | `add n/NAME l/LOCATION sd/START_DATE ed/END_DATE d/DESCRIPTION [t/TAG]...` | `add n/Fundraising l/Tampines S sd/31-09-2018 ed/31-09-2018 st/13:00 et/18:00 d/Raising funds t/fundraiser t/charity` | <> +| *Delete* | `delete EVENT_INDEX` | `delete 3` | <> +| *Edit* | `edit EVENT_INDEX [n/NAME] [l/LOCATION] [sd/START_DATE] [ed/END_DATE] [d/DESCRIPTION] [t/TAG]...` | `edit 2 n/Fundraiser` | <> +| *List* | `list` | `list` | <> +|======================================================================= + +=== Record Management + +[width="100%",cols="10%, 30%, 30%, 30%",options="header",] +|======================================================================= +| Command | Format | Example | Section Link +| *Add* | `add VOLUNTEER_INDEX [h/HOURS] [r/REMARKS]` | `add 1 h/1` | <> +| *Delete* | `delete VOLUNTEER_INDEX` | `delete 1` | <> +| *Edit* | `edit VOLUNTEER_INDEX h/HOURS [VOLUNTEER_INDEX]` | `edit 1 h/8` | <> +| *Manage* | `manage EVENT_INDEX` | `manage 1` | <> +|======================================================================= + + +== Glossary +[width="100%",cols="30%,70%",options="header",] +|======================================================================= +| Term| Explanation +| *GUI*| Graphical User Interface. +|======================================================================= + == FAQ *Q*: How do I transfer my data to another Computer? + -*A*: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous Address Book folder. - -== Command Summary - -* *Add* `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` + -e.g. `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague` -* *Clear* : `clear` -* *Delete* : `delete INDEX` + -e.g. `delete 3` -* *Edit* : `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]...` + -e.g. `edit 2 n/James Lee e/jameslee@example.com` -* *Find* : `find KEYWORD [MORE_KEYWORDS]` + -e.g. `find James Jake` -* *List* : `list` -* *Help* : `help` -* *Select* : `select INDEX` + -e.g.`select 2` -* *History* : `history` -* *Undo* : `undo` -* *Redo* : `redo` +*A*: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous SocialCare folder. + diff --git a/docs/diagrams/Command_Add_SequenceDiagram.pptx b/docs/diagrams/Command_Add_SequenceDiagram.pptx new file mode 100644 index 000000000000..20a16815d352 Binary files /dev/null and b/docs/diagrams/Command_Add_SequenceDiagram.pptx differ diff --git a/docs/diagrams/Command_Event.pptx b/docs/diagrams/Command_Event.pptx new file mode 100644 index 000000000000..9fc110d0cc0d Binary files /dev/null and b/docs/diagrams/Command_Event.pptx differ diff --git a/docs/diagrams/Command_Manage_SequenceDiagram.pptx b/docs/diagrams/Command_Manage_SequenceDiagram.pptx new file mode 100644 index 000000000000..48aadce60375 Binary files /dev/null and b/docs/diagrams/Command_Manage_SequenceDiagram.pptx differ diff --git a/docs/diagrams/Command_Overview_SequenceDiagram.pptx b/docs/diagrams/Command_Overview_SequenceDiagram.pptx new file mode 100644 index 000000000000..64fb4941d0bd Binary files /dev/null and b/docs/diagrams/Command_Overview_SequenceDiagram.pptx differ diff --git a/docs/diagrams/Command_Record.pptx b/docs/diagrams/Command_Record.pptx new file mode 100644 index 000000000000..28fcda695523 Binary files /dev/null and b/docs/diagrams/Command_Record.pptx differ diff --git a/docs/diagrams/Command_Switch.pptx b/docs/diagrams/Command_Switch.pptx new file mode 100644 index 000000000000..3d6ce12fb68f Binary files /dev/null and b/docs/diagrams/Command_Switch.pptx differ diff --git a/docs/diagrams/Command_Switch_SequenceDiagram.pptx b/docs/diagrams/Command_Switch_SequenceDiagram.pptx new file mode 100644 index 000000000000..7a06c3da288b Binary files /dev/null and b/docs/diagrams/Command_Switch_SequenceDiagram.pptx differ diff --git a/docs/diagrams/UiLabelled.pptx b/docs/diagrams/UiLabelled.pptx new file mode 100644 index 000000000000..8c483d7ea2f7 Binary files /dev/null and b/docs/diagrams/UiLabelled.pptx differ diff --git a/docs/diagrams/UndoRedoSequenceDiagram.pptx b/docs/diagrams/UndoRedoSequenceDiagram.pptx index 5ccc1042caac..5211d28b6b78 100644 Binary files a/docs/diagrams/UndoRedoSequenceDiagram.pptx and b/docs/diagrams/UndoRedoSequenceDiagram.pptx differ diff --git a/docs/images/CurrentVolunteerCert.png b/docs/images/CurrentVolunteerCert.png new file mode 100644 index 000000000000..286ca94f6265 Binary files /dev/null and b/docs/images/CurrentVolunteerCert.png differ diff --git a/docs/images/UI_Mockup.png b/docs/images/UI_Mockup.png new file mode 100644 index 000000000000..cb63d09f3f93 Binary files /dev/null and b/docs/images/UI_Mockup.png differ diff --git a/docs/images/Ui.png b/docs/images/Ui.png index 5ec9c527b49c..6cbf7294d3a0 100644 Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ diff --git a/docs/images/UiLabelled.png b/docs/images/UiLabelled.png new file mode 100644 index 000000000000..a5083e1f346b Binary files /dev/null and b/docs/images/UiLabelled.png differ diff --git a/docs/images/afiqlattif.png b/docs/images/afiqlattif.png new file mode 100644 index 000000000000..5f0e4b043f3b Binary files /dev/null and b/docs/images/afiqlattif.png differ diff --git a/docs/images/command_add_event_after.png b/docs/images/command_add_event_after.png new file mode 100644 index 000000000000..a4473cf06560 Binary files /dev/null and b/docs/images/command_add_event_after.png differ diff --git a/docs/images/command_add_event_before.png b/docs/images/command_add_event_before.png new file mode 100644 index 000000000000..3218233710a8 Binary files /dev/null and b/docs/images/command_add_event_before.png differ diff --git a/docs/images/command_add_sd.png b/docs/images/command_add_sd.png new file mode 100644 index 000000000000..657af328065d Binary files /dev/null and b/docs/images/command_add_sd.png differ diff --git a/docs/images/command_clear_after.png b/docs/images/command_clear_after.png new file mode 100644 index 000000000000..330e7e173589 Binary files /dev/null and b/docs/images/command_clear_after.png differ diff --git a/docs/images/command_clear_before.png b/docs/images/command_clear_before.png new file mode 100644 index 000000000000..398640e11dba Binary files /dev/null and b/docs/images/command_clear_before.png differ diff --git a/docs/images/command_delete_event_after.png b/docs/images/command_delete_event_after.png new file mode 100644 index 000000000000..acc22cbcb453 Binary files /dev/null and b/docs/images/command_delete_event_after.png differ diff --git a/docs/images/command_delete_event_before.png b/docs/images/command_delete_event_before.png new file mode 100644 index 000000000000..e7d1a8fb2e5b Binary files /dev/null and b/docs/images/command_delete_event_before.png differ diff --git a/docs/images/command_edit_event_after.png b/docs/images/command_edit_event_after.png new file mode 100644 index 000000000000..49d651c2eafb Binary files /dev/null and b/docs/images/command_edit_event_after.png differ diff --git a/docs/images/command_edit_event_before.png b/docs/images/command_edit_event_before.png new file mode 100644 index 000000000000..75629d6451b0 Binary files /dev/null and b/docs/images/command_edit_event_before.png differ diff --git a/docs/images/command_event_add_before.png b/docs/images/command_event_add_before.png new file mode 100644 index 000000000000..35596deca5c3 Binary files /dev/null and b/docs/images/command_event_add_before.png differ diff --git a/docs/images/command_event_add_before_after1.png b/docs/images/command_event_add_before_after1.png new file mode 100644 index 000000000000..f24222b4e216 Binary files /dev/null and b/docs/images/command_event_add_before_after1.png differ diff --git a/docs/images/command_event_add_before_after2.png b/docs/images/command_event_add_before_after2.png new file mode 100644 index 000000000000..b83b2a676d6e Binary files /dev/null and b/docs/images/command_event_add_before_after2.png differ diff --git a/docs/images/command_event_delete_before.png b/docs/images/command_event_delete_before.png new file mode 100644 index 000000000000..52bf24dcbdb9 Binary files /dev/null and b/docs/images/command_event_delete_before.png differ diff --git a/docs/images/command_event_delete_before_after.png b/docs/images/command_event_delete_before_after.png new file mode 100644 index 000000000000..41b0c44cf4ef Binary files /dev/null and b/docs/images/command_event_delete_before_after.png differ diff --git a/docs/images/command_event_edit_before.png b/docs/images/command_event_edit_before.png new file mode 100644 index 000000000000..76ed84b599f1 Binary files /dev/null and b/docs/images/command_event_edit_before.png differ diff --git a/docs/images/command_event_edit_before_after.png b/docs/images/command_event_edit_before_after.png new file mode 100644 index 000000000000..86932353d37a Binary files /dev/null and b/docs/images/command_event_edit_before_after.png differ diff --git a/docs/images/command_event_list.png b/docs/images/command_event_list.png new file mode 100644 index 000000000000..35596deca5c3 Binary files /dev/null and b/docs/images/command_event_list.png differ diff --git a/docs/images/command_exportcert_ad.png b/docs/images/command_exportcert_ad.png new file mode 100644 index 000000000000..f34f4a7c64e1 Binary files /dev/null and b/docs/images/command_exportcert_ad.png differ diff --git a/docs/images/command_exportcert_sd_1.png b/docs/images/command_exportcert_sd_1.png new file mode 100644 index 000000000000..ca87fb98c527 Binary files /dev/null and b/docs/images/command_exportcert_sd_1.png differ diff --git a/docs/images/command_exportcert_sd_2.png b/docs/images/command_exportcert_sd_2.png new file mode 100644 index 000000000000..59f9b35a573d Binary files /dev/null and b/docs/images/command_exportcert_sd_2.png differ diff --git a/docs/images/command_manage.png b/docs/images/command_manage.png new file mode 100644 index 000000000000..b9892555e716 Binary files /dev/null and b/docs/images/command_manage.png differ diff --git a/docs/images/command_manage_sd.png b/docs/images/command_manage_sd.png new file mode 100644 index 000000000000..a1106b806b36 Binary files /dev/null and b/docs/images/command_manage_sd.png differ diff --git a/docs/images/command_manage_view.png b/docs/images/command_manage_view.png new file mode 100644 index 000000000000..2d293ef69169 Binary files /dev/null and b/docs/images/command_manage_view.png differ diff --git a/docs/images/command_overview.png b/docs/images/command_overview.png new file mode 100644 index 000000000000..9d3809b7ecf2 Binary files /dev/null and b/docs/images/command_overview.png differ diff --git a/docs/images/command_overview_sd.png b/docs/images/command_overview_sd.png new file mode 100644 index 000000000000..cc2fb6581536 Binary files /dev/null and b/docs/images/command_overview_sd.png differ diff --git a/docs/images/command_record_add.png b/docs/images/command_record_add.png new file mode 100644 index 000000000000..3af0c79643f8 Binary files /dev/null and b/docs/images/command_record_add.png differ diff --git a/docs/images/command_record_add_after1.png b/docs/images/command_record_add_after1.png new file mode 100644 index 000000000000..b74d111dedfa Binary files /dev/null and b/docs/images/command_record_add_after1.png differ diff --git a/docs/images/command_record_add_after2.png b/docs/images/command_record_add_after2.png new file mode 100644 index 000000000000..acf65287fca4 Binary files /dev/null and b/docs/images/command_record_add_after2.png differ diff --git a/docs/images/command_record_add_volunteerIndex.png b/docs/images/command_record_add_volunteerIndex.png new file mode 100644 index 000000000000..db249cc85091 Binary files /dev/null and b/docs/images/command_record_add_volunteerIndex.png differ diff --git a/docs/images/command_record_delete.png b/docs/images/command_record_delete.png new file mode 100644 index 000000000000..552c301a4b23 Binary files /dev/null and b/docs/images/command_record_delete.png differ diff --git a/docs/images/command_record_edit.png b/docs/images/command_record_edit.png new file mode 100644 index 000000000000..6838168a13f4 Binary files /dev/null and b/docs/images/command_record_edit.png differ diff --git a/docs/images/command_record_edit_after.png b/docs/images/command_record_edit_after.png new file mode 100644 index 000000000000..8d4e5039f688 Binary files /dev/null and b/docs/images/command_record_edit_after.png differ diff --git a/docs/images/command_record_edit_volunteerIndex.png b/docs/images/command_record_edit_volunteerIndex.png new file mode 100644 index 000000000000..755d66171ec0 Binary files /dev/null and b/docs/images/command_record_edit_volunteerIndex.png differ diff --git a/docs/images/command_record_manage_eventIndex.png b/docs/images/command_record_manage_eventIndex.png new file mode 100644 index 000000000000..385480fee4c9 Binary files /dev/null and b/docs/images/command_record_manage_eventIndex.png differ diff --git a/docs/images/command_switch.png b/docs/images/command_switch.png new file mode 100644 index 000000000000..64a505b4049e Binary files /dev/null and b/docs/images/command_switch.png differ diff --git a/docs/images/command_switch_after.png b/docs/images/command_switch_after.png new file mode 100644 index 000000000000..d947f8fc9bf5 Binary files /dev/null and b/docs/images/command_switch_after.png differ diff --git a/docs/images/command_switch_before.png b/docs/images/command_switch_before.png new file mode 100644 index 000000000000..5b77b5f6d2be Binary files /dev/null and b/docs/images/command_switch_before.png differ diff --git a/docs/images/command_switch_sd.png b/docs/images/command_switch_sd.png new file mode 100644 index 000000000000..660253fd1eaa Binary files /dev/null and b/docs/images/command_switch_sd.png differ diff --git a/docs/images/command_volunteer_add_after1.png b/docs/images/command_volunteer_add_after1.png new file mode 100644 index 000000000000..fc33bd9c6dc6 Binary files /dev/null and b/docs/images/command_volunteer_add_after1.png differ diff --git a/docs/images/command_volunteer_add_after2.png b/docs/images/command_volunteer_add_after2.png new file mode 100644 index 000000000000..542c6d8f14f3 Binary files /dev/null and b/docs/images/command_volunteer_add_after2.png differ diff --git a/docs/images/command_volunteer_add_before.png b/docs/images/command_volunteer_add_before.png new file mode 100644 index 000000000000..5623fb3ba947 Binary files /dev/null and b/docs/images/command_volunteer_add_before.png differ diff --git a/docs/images/command_volunteer_delete.png b/docs/images/command_volunteer_delete.png new file mode 100644 index 000000000000..f239ed6d1d01 Binary files /dev/null and b/docs/images/command_volunteer_delete.png differ diff --git a/docs/images/command_volunteer_delete_after.png b/docs/images/command_volunteer_delete_after.png new file mode 100644 index 000000000000..b9fd2bae74bb Binary files /dev/null and b/docs/images/command_volunteer_delete_after.png differ diff --git a/docs/images/command_volunteer_delete_before.png b/docs/images/command_volunteer_delete_before.png new file mode 100644 index 000000000000..90581238d0ff Binary files /dev/null and b/docs/images/command_volunteer_delete_before.png differ diff --git a/docs/images/command_volunteer_edit.png b/docs/images/command_volunteer_edit.png new file mode 100644 index 000000000000..f25d37c497ae Binary files /dev/null and b/docs/images/command_volunteer_edit.png differ diff --git a/docs/images/command_volunteer_edit_after.png b/docs/images/command_volunteer_edit_after.png new file mode 100644 index 000000000000..aea2eccaeef6 Binary files /dev/null and b/docs/images/command_volunteer_edit_after.png differ diff --git a/docs/images/command_volunteer_edit_before.png b/docs/images/command_volunteer_edit_before.png new file mode 100644 index 000000000000..e41ec8ba662c Binary files /dev/null and b/docs/images/command_volunteer_edit_before.png differ diff --git a/docs/images/command_volunteer_list.png b/docs/images/command_volunteer_list.png new file mode 100644 index 000000000000..8f799c3b503e Binary files /dev/null and b/docs/images/command_volunteer_list.png differ diff --git a/docs/images/imarbles.png b/docs/images/imarbles.png new file mode 100644 index 000000000000..54fd5fa28dc3 Binary files /dev/null and b/docs/images/imarbles.png differ diff --git a/docs/images/kratious.png b/docs/images/kratious.png new file mode 100644 index 000000000000..e2557b52a897 Binary files /dev/null and b/docs/images/kratious.png differ diff --git a/docs/images/sharan8.png b/docs/images/sharan8.png new file mode 100644 index 000000000000..3aecf1bb1893 Binary files /dev/null and b/docs/images/sharan8.png differ diff --git a/docs/team/afiqlattif.adoc b/docs/team/afiqlattif.adoc new file mode 100644 index 000000000000..86a6cc7575ed --- /dev/null +++ b/docs/team/afiqlattif.adoc @@ -0,0 +1,58 @@ += Afiq Lattif - Project Portfolio +:site-section: AboutUs +:imagesDir: ../images +:stylesDir: ../stylesheets +:repoURL: https://github.com/CS2103-AY1819S1-W16-2/main + + +== PROJECT: SocialCare + +:sectnums: +== Overview + +This portfolio records my contributions to the SocialCare project, under the CS2103T Software Engineering module offered by the School of Computing in NUS. + +SocialCare empowers volunteer managers to revolutionise the way they manage their resources. With features such as Statistics and Exporting of Certificates with a simple command, the organisational process has never been as effective. + +With my role as a Developer for this project, I implemented *volunteer management functions*, ensuring that the organizational process is simpler yet systematic. + +== Summary of contributions + +My contributions to the project mainly focuses on volunteer management. + +* *Major enhancement*: Added *commands to manage volunteers* +** What it does: Allows the user to manage volunteer details with commands such as add, edit and delete. +** Justification: Streamlines the management of volunteers to fit the volunteer organisation context +** Highlights: Affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands by implementing additional fields and checks. + +* *Minor enhancement*: Added a Birthday util that exports birth date to a readable format and checks if birth day is before current date. + +* *Code contributed*: +Here is a https://nus-cs2103-ay1819s1.github.io/cs2103-dashboard/#=undefined&search=afiqlattif[link] +to my code on the Project Code Dashboard. + +* *Other contributions*: + +** Documentation: +*** Did cosmetic tweaks to existing contents of the User Guide: link:https://github.com/CS2103-AY1819S1-W16-2/main/pull/173[#173] +*** Revised content in the Developer Guide: link:https://github.com/CS2103-AY1819S1-W16-2/main/pull/72[#72], link:https://github.com/CS2103-AY1819S1-W16-2/main/pull/121[#121] +** Community: +*** Reviewed PRs for team members (with non-trivial comments) : link:https://github.com/CS2103-AY1819S1-W16-2/main/pull/144[#144], link:https://github.com/CS2103-AY1819S1-W16-2/main/pull/174[#174] + +== Contributions to the User Guide + + +|=== +|_Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users._ +|=== + +include::../UserGuide.adoc[tag=volunteermanagement] + +== Contributions to the Developer Guide + +|=== +|_Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project._ +|=== + +include::../DeveloperGuide.adoc[tag=command-add] + diff --git a/docs/team/imarbles.adoc b/docs/team/imarbles.adoc new file mode 100644 index 000000000000..0029a59f04d4 --- /dev/null +++ b/docs/team/imarbles.adoc @@ -0,0 +1,83 @@ += Amabel Yeo - Project Portfolio +:site-section: AboutUs +:imagesDir: ../images +:stylesDir: ../stylesheets +:repoURL: https://github.com/CS2103-AY1819S1-W16-2/main/pull + +== PROJECT: SocialCare + +:sectnums: +== Overview + +This portfolio page documents my involvement in SocialCare, a project done as part of the CS21303T Software Engineering module taught in NUS. +For this project, my team had the goal to _'harness the potential of software to create sustainable social change'_. + +With our goal in mind, we developed SocialCare, a desktop application made for social welfare organizations. +This application is designed to help manage volunteers and events effectively. This is done through the Command Line Interface (CLI), which help users to interact with the application; and the Graphical User Interface (GUI), which displays information in a user-friendly manner. + +My main role as a developer for SocialCare was to implement *record management functions*, which enable users to do the following: + +* View volunteers assigned to an event +* Assign volunteers to an event +* Update volunteering records for volunteers +* Delete volunteering records of volunteers + +== Summary of Contributions +* *Major enhancement*: +Added commands to *manage volunteer records* +** What it does: +The commands implemented allow users to manage volunteering records. +They will be able to assign volunteers to events and update the number of hours contributed by the volunteer. + +** Justification: +These functions are part of the core requirements for the application because we want users to be able to effectively manage volunteering records. + +** Highlights: +This enhancement is completely new and required an in-depth analysis of design alternatives. +It was challenging as to properly implement this, a complete understanding of all code components was needed. + +* *Minor enhancements*: +** Added a command to allow users to *switch between panels*. +** Created charts for the `overview` command. + +* *Code contributed*: +Here is a https://nus-cs2103-ay1819s1.github.io/cs2103-dashboard/#=undefined&search=imarbles[link] +to my code on the Project Code Dashboard. + + +* *Other contributions*: + +** Project management: +*** Set up the team repository on GitHub + +*** Ensured that project deliverables were done on time and in the right format +** Documentation: +*** Did cosmetic tweaks to existing contents of the User Guide: link:{repoURL}/76/[#76], link:{repoURL}/129/[#129] +*** Rewrote the quick start section of the User Guide: link:{repoURL}/154/[#154] +*** Revised content for the Logic component in the Developer Guide: link:{repoURL}/93/[#93] +** Community: +*** Reviewed PRs for team members (with non-trivial review comments): link:{repoURL}/58/[#58], link:{repoURL}/109/[#109], link:{repoURL}/114/[#114] +** Tools: +*** Integrated Travis to the Github repository + +== Contributions to the User Guide + + +|=== +| Below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users._ +|=== + +include::../UserGuide.adoc[tag=command-record] +include::../UserGuide.adoc[tag=command-switch] + + +== Contributions to the Developer Guide + +|=== +| Below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project._ +|=== + +include::../DeveloperGuide.adoc[tag=command-manage] +include::../DeveloperGuide.adoc[tag=command-switch] + + diff --git a/docs/team/kratious.adoc b/docs/team/kratious.adoc new file mode 100644 index 000000000000..f64bbde48ca7 --- /dev/null +++ b/docs/team/kratious.adoc @@ -0,0 +1,70 @@ += Sem Jing Han - Project Portfolio +:site-section: AboutUs +:imagesDir: ../images +:stylesDir: ../stylesheets +:pullURL: https://github.com/CS2103-AY1819S1-W16-2/main/pull + + +== PROJECT: SocialCare + +--- +:sectnums: +== Overview + +This portfolio documents my involvement in the SocialCare project that was developed under the CS2103T (Software Engineering) module taken in the National University of Singapore (NUS). + +SocialCare is a desktop application designed to serve the *volunteer and event management* needs of social welfare organizations. +The main aim of the project was to streamline manual and inefficient processes faced by administrators of such organizations. +Users primarily interact with the application using a Command Line Interface (CLI) with elements of a Graphical User Interface (GUI) to display information. + +My primary role as a developer for SocialCare involved implementing *event management functions* as well as handling *extensive user interface improvements*. + + + +== Summary of Contributions + +* *Major enhancement*: added the ability to manage and display *event records* +** What it does: This feature allows the user to create and manage events that span a period of time. +** Justification: This feature improves the product significantly because a user is able to display and keep track of events by the organisation. This is a core requirement to the application as volunteers have to be assigned to events for basic operations. +** Highlights: +This enhancement is one of the major building blocks of the system and affects majority of the other components. It required an in-depth analysis of design alternatives. The implementation too was challenging as other components are dependent on this component. + +* *Minor enhancement*: added an overview command that allows the user to have a statistical overview of existing volunteers and events. + +* *Code contributed*: Here is a https://nus-cs2103-ay1819s1.github.io/cs2103-dashboard/#=undefined&search=kratious[link] to my code on the Project Code Dashboard. + +* *Other contributions*: + +** Project management: +*** Managed releases `v1.1` - `v1.4` (4 releases) on GitHub +*** Applied upstream bug fix: link:{pullURL}/78/[#78] +** Enhancements to existing features: +*** Updated the user interface aesthetics and behaviour: link:{pullURL}/92/[#92], link:{pullURL}/158/[#158], link:{pullURL}/243/[#243] +** Documentation: +*** Did cosmetic tweaks to existing contents of the Developer Guide: link:{pullURL}/118/[#118], link:{pullURL}/128/[#128] +** Community: +*** PRs reviewed (with non-trivial review comments): link:{pullURL}/58/[#58], link:{pullURL}/232/[#232] +*** Enquired about and resolved a team issue on the forum: https://github.com/nus-cs2103-AY1819S1/forum/issues/134[#134] +** Tools: +*** Integrated a new Github plugin (Coveralls) to the team repository + + +== Contributions to the User Guide + + +|=== +|_Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users._ +|=== + +include::../UserGuide.adoc[tag=eventmanagement] + +== Contributions to the Developer Guide + +|=== +|_Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project._ +|=== + +include::../DeveloperGuide.adoc[tag=eventmanagement] + +include::../DeveloperGuide.adoc[tag=command-overview] + diff --git a/docs/team/scrubbius.adoc b/docs/team/scrubbius.adoc new file mode 100644 index 000000000000..9be665286c64 --- /dev/null +++ b/docs/team/scrubbius.adoc @@ -0,0 +1,72 @@ += Ngoh Wen Jun - Project Portfolio +:site-section: AboutUs +:imagesDir: ../images +:stylesDir: ../stylesheets + +== PROJECT: SocialCare + +--- + +== Overview + +SocialCare morphs the given AddressBook - Level 4 application into a volunteer management system that allows Social Welfare Organisations to better manage their volunteers & events, and gain further statistical insights from the data. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC. + +== Summary of contributions + +* *Major enhancement*: added *the ability to undo/redo previous commands* +** What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command. +** Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them. +** Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands. +** Credits: _{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}_ + +* *Minor enhancement*: added a history command that allows the user to navigate to previous commands using up/down keys. + +* *Code contributed*: [https://github.com[Functional code]] [https://github.com[Test code]] _{give links to collated code files}_ + +* *Other contributions*: + +** Project management: +*** Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub +** Enhancements to existing features: +*** Updated the GUI color scheme (Pull requests https://github.com[#33], https://github.com[#34]) +*** Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests https://github.com[#36], https://github.com[#38]) +** Documentation: +*** Did cosmetic tweaks to existing contents of the User Guide: https://github.com[#14] +** Community: +*** PRs reviewed (with non-trivial review comments): https://github.com[#12], https://github.com[#32], https://github.com[#19], https://github.com[#42] +*** Contributed to forum discussions (examples: https://github.com[1], https://github.com[2], https://github.com[3], https://github.com[4]) +*** Reported bugs and suggestions for other teams in the class (examples: https://github.com[1], https://github.com[2], https://github.com[3]) +*** Some parts of the history feature I added was adopted by several other class mates (https://github.com[1], https://github.com[2]) +** Tools: +*** Integrated a third party library (Natty) to the project (https://github.com[#42]) +*** Integrated a new Github plugin (CircleCI) to the team repo + +_{you can add/remove categories in the list above}_ + +== Contributions to the User Guide + + +|=== +|_Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users._ +|=== + +include::../UserGuide.adoc[tag=undoredo] + +include::../UserGuide.adoc[tag=dataencryption] + +== Contributions to the Developer Guide + +|=== +|_Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project._ +|=== + +include::../DeveloperGuide.adoc[tag=undoredo] + +include::../DeveloperGuide.adoc[tag=dataencryption] + + +== PROJECT: PowerPointLabs + +--- + +_{Optionally, you may include other projects in your portfolio.}_ diff --git a/docs/team/sharan8.adoc b/docs/team/sharan8.adoc new file mode 100644 index 000000000000..3eaade928fe9 --- /dev/null +++ b/docs/team/sharan8.adoc @@ -0,0 +1,91 @@ += Thangavel Sharan - Project Portfolio +:site-section: AboutUs +:imagesDir: ../images +:stylesDir: ../stylesheets +:pullURL: https://github.com/CS2103-AY1819S1-W16-2/main/pull + +== PROJECT: _SocialCare_ + +--- + +== Overview +This project portfolio page serves to document my contributions to _SocialCare_, a *software engineering project* that was +undertaken as part of the National University of Singapore (NUS) School of Computing's beginner Software Engineering +module, CS2103T. More information on this module can be found +https://nus-cs2103-ay1819s1.github.io/cs2103-website/admin/index.html[here]. + +_SocialCare_ is an *event and volunteer management system* for administrators of social welfare organisations, which runs on desktops. +The user interacts with it using the Command Line Interface (CLI), and it has a Graphical User Interface (GUI) +created using https://docs.oracle.com/javafx/2/overview/jfxpub-overview.htm[JavaFX]. The application is written in Java, +and has about 10,000 lines of code. + +Key Features of _SocialCare_: + +* Add, remove and store volunteers and events. +* Assign volunteers to events. +* Create event records for each volunteer consisting of the event and volunteer IDs, hours contributed and related +remarks. +* Export a PDF certificate detailing a volunteer’s involvement with the organisation (event records, contributed hours). + +Through the use of the CLI, _SocialCare_ enables the above functionalities to be executed faster than a typical +mouse/GUI driven application. + +== Summary of contributions + +This section summarizes my contributions to this project and to my fellow course mates throughout the course of the module. It includes enhancements made and a link to the code that I contributed as well. + +* *Major enhancement*: I added *the ability to export volunteer certificates in PDF format.* +** _What it does_: This feature allows the user to export a volunteer’s event records and contributed hours in the form +of a PDF certificate. +** _Justification_: This feature improves the product significantly as it automates a task that is currently done manually by referencing files of volunteer records and painstakingly entering information into a word document. It also offers the user a way to access information from outside of the application as well (via portable +and printable PDF files). +** _Highlights_: This enhancement involved an in-depth analysis of available external open source libraries, and +meticulous design of the PDF document to be exported. +** _Credits_: This feature was developed with the use of https://pdfbox.apache.org/team.html[Apache PDFBox], which +provides the functionality to create and write to PDF files. + +* *Minor enhancement*: I added the *total volunteer count to the status bar*. This enhancement is in line with our +application’s intention to provide the user with easy access to useful information pertaining to volunteers. + +* *Code contributed*: Here is a https://nus-cs2103-ay1819s1.github.io/cs2103-dashboard/#=undefined&search=sharan8[link] +to my code on the Project Code Dashboard. + +* *Other contributions*: + +** Documentation: +*** Revised the introduction sections of the +https://github.com/CS2103-AY1819S1-W16-2/main/blob/master/README.adoc[README] and +https://github.com/CS2103-AY1819S1-W16-2/main/blob/master/docs/DeveloperGuide.adoc[Developer Guide] ({pullURL}/109[#109]) +** Community: +*** Reviewed PRs (with non-trivial review comments): {pullURL}/92[#92], {pullURL}/107[#107], {pullURL}/114[#114], {pullURL}/232[#232] +*** Involved forum members in the resolution of a design consideration: https://github.com/nus-cs2103-AY1819S1/forum/issues/114[#114] +*** Shared a personal learning point with forum members: https://github.com/nus-cs2103-AY1819S1/forum/issues/143[#143] +*** Provided inspiration for the implementation of the import/export csv/xml feature, specifically through my handling of file export to main and backup filepaths in the `exportcert` feature I added. +** Tools: +*** Integrated a third party library (https://pdfbox.apache.org/index.html[Apache PDFBox]) to the project +({pullURL}/161[#161]). +** Project conceptualisation: +*** Set up and managed a shared +https://docs.google.com/document/d/19iV64xK0EwaV8kjMaP72P1G7iGKKXtEX2my5M-QowKc/edit?usp=sharing[Brainstorming Canvas] +to brainstorm on product morphing ideas using the 'Target User Profile-Problem-Value Proposition' framework. +*** Conceptualised and validated the idea for _SocialCare_ through conversing with staff from 2 +social welfare organisations that I have worked with in the past, who are part of our intended target group. +*** Contacted a software engineer from the industry to find out how Extreme Programming is actually employed, and shared the takeaways with my group and classmates. + +== Contributions to the User Guide + +|=== +|_Given below is the section I contributed to the User Guide pertaining to the feature that I implemented, `exportcert`. It showcases my ability to write and design documentation targeting +end-users._ +|=== + +include::../UserGuide.adoc[tag=exportcert-sharan-ppp] + +== Contributions to the Developer Guide + +|=== +|_Given below is an excerpt from the section I contributed to the Developer Guide. It showcases my ability to write technical +documentation which showcases the technical depth of my contributions to the project, along with my ability to critically analyse design considerations._ +|=== + +include::../DeveloperGuide.adoc[tag=exportcert-sharan-ppp] diff --git a/docs/templates/LICENSE b/docs/templates/LICENSE index 2073b44dee64..b07e680ae156 100644 --- a/docs/templates/LICENSE +++ b/docs/templates/LICENSE @@ -5,7 +5,7 @@ MIT License Copyright (C) 2012-2018 Dan Allen, Ryan Waldron and the Asciidoctor Project -Permission is hereby granted, free of charge, to any person obtaining a copy +Permission is hereby granted, free of charge, to any volunteer obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index ecdd043a4f81..89f3e6c35131 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -40,7 +40,7 @@ */ public class MainApp extends Application { - public static final Version VERSION = new Version(0, 6, 0, true); + public static final Version VERSION = new Version(1, 3, 3, true); private static final Logger logger = LogsCenter.getLogger(MainApp.class); @@ -87,14 +87,14 @@ private Model initModelManager(Storage storage, UserPrefs userPrefs) { try { addressBookOptional = storage.readAddressBook(); if (!addressBookOptional.isPresent()) { - logger.info("Data file not found. Will be starting with a sample AddressBook"); + logger.info("Data file not found. Will be starting with sample SocialCare data"); } initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook); } catch (DataConversionException e) { - logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook"); + logger.warning("Data file not in the correct format. Will be starting with empty data"); initialData = new AddressBook(); } catch (IOException e) { - logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); + logger.warning("Problem while reading from the file. Will be starting with empty data"); initialData = new AddressBook(); } @@ -159,7 +159,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) { + "Using default user prefs"); initializedPrefs = new UserPrefs(); } catch (IOException e) { - logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); + logger.warning("Problem while reading from the file. Will be starting with empty data"); initializedPrefs = new UserPrefs(); } diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/seedu/address/commons/core/Config.java index e978d621e086..533faffe55a6 100644 --- a/src/main/java/seedu/address/commons/core/Config.java +++ b/src/main/java/seedu/address/commons/core/Config.java @@ -13,7 +13,7 @@ public class Config { public static final Path DEFAULT_CONFIG_FILE = Paths.get("config.json"); // Config values customizable through config file - private String appTitle = "Address App"; + private String appTitle = "SocialCare"; private Level logLevel = Level.INFO; private Path userPrefsFilePath = Paths.get("preferences.json"); diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java index 1deb3a1e4695..27736b050517 100644 --- a/src/main/java/seedu/address/commons/core/Messages.java +++ b/src/main/java/seedu/address/commons/core/Messages.java @@ -5,9 +5,19 @@ */ public class Messages { + // General messages public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command"; public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; - public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid"; - public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; + // Volunteers messages + + public static final String MESSAGE_INVALID_VOLUNTEER_DISPLAYED_INDEX = "The volunteer index provided is invalid."; + public static final String MESSAGE_VOLUNTEERS_LISTED_OVERVIEW = "%1$d volunteers listed!"; + + // Event messages + public static final String MESSAGE_INVALID_EVENT_DISPLAYED_INDEX = "The event index provided is invalid"; + public static final String MESSAGE_EVENTS_LISTED_OVERVIEW = "%1$d events listed!"; + + // Record messages + public static final String MESSAGE_INVALID_RECORD_DISPLAYED_INDEX = "The record index provided is invalid"; } diff --git a/src/main/java/seedu/address/commons/events/model/AddressBookChangedEvent.java b/src/main/java/seedu/address/commons/events/model/AddressBookChangedEvent.java index b72ad4740e5a..5acf29a2ebed 100644 --- a/src/main/java/seedu/address/commons/events/model/AddressBookChangedEvent.java +++ b/src/main/java/seedu/address/commons/events/model/AddressBookChangedEvent.java @@ -14,6 +14,6 @@ public AddressBookChangedEvent(ReadOnlyAddressBook data) { @Override public String toString() { - return "number of persons " + data.getPersonList().size(); + return "number of volunteers " + data.getVolunteerList().size(); } } diff --git a/src/main/java/seedu/address/commons/events/ui/ContextChangeEvent.java b/src/main/java/seedu/address/commons/events/ui/ContextChangeEvent.java new file mode 100644 index 000000000000..438ef64b87ef --- /dev/null +++ b/src/main/java/seedu/address/commons/events/ui/ContextChangeEvent.java @@ -0,0 +1,23 @@ +package seedu.address.commons.events.ui; + +import seedu.address.commons.events.BaseEvent; + +/** + * Represents a selection change in the Event List Panel + */ +public class ContextChangeEvent extends BaseEvent { + private final String contextId; + + public ContextChangeEvent(String contextId) { + this.contextId = contextId; + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + + public String getNewContext() { + return contextId; + } +} diff --git a/src/main/java/seedu/address/commons/events/ui/EventPanelSelectionChangedEvent.java b/src/main/java/seedu/address/commons/events/ui/EventPanelSelectionChangedEvent.java new file mode 100644 index 000000000000..06c12d802e32 --- /dev/null +++ b/src/main/java/seedu/address/commons/events/ui/EventPanelSelectionChangedEvent.java @@ -0,0 +1,26 @@ +package seedu.address.commons.events.ui; + +import seedu.address.commons.events.BaseEvent; +import seedu.address.model.event.Event; + +/** + * Represents a selection change in the Event List Panel + */ +public class EventPanelSelectionChangedEvent extends BaseEvent { + + + private final Event newSelection; + + public EventPanelSelectionChangedEvent(Event newSelection) { + this.newSelection = newSelection; + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + + public Event getNewSelection() { + return newSelection; + } +} diff --git a/src/main/java/seedu/address/commons/events/ui/JumpToEventListRequestEvent.java b/src/main/java/seedu/address/commons/events/ui/JumpToEventListRequestEvent.java new file mode 100644 index 000000000000..ccf9a7745327 --- /dev/null +++ b/src/main/java/seedu/address/commons/events/ui/JumpToEventListRequestEvent.java @@ -0,0 +1,21 @@ +package seedu.address.commons.events.ui; + +import seedu.address.commons.core.index.Index; +import seedu.address.commons.events.BaseEvent; + +/** + * Indicates a request to jump to the list of events + */ +public class JumpToEventListRequestEvent extends BaseEvent { + + public final int targetIndex; + + public JumpToEventListRequestEvent(Index targetIndex) { + this.targetIndex = targetIndex.getZeroBased(); + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } +} diff --git a/src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java b/src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java index a890f8b47350..5c9224e60379 100644 --- a/src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java +++ b/src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java @@ -4,7 +4,7 @@ import seedu.address.commons.events.BaseEvent; /** - * Indicates a request to jump to the list of persons + * Indicates a request to jump to the list of volunteers */ public class JumpToListRequestEvent extends BaseEvent { diff --git a/src/main/java/seedu/address/commons/events/ui/OverviewPanelChangedEvent.java b/src/main/java/seedu/address/commons/events/ui/OverviewPanelChangedEvent.java new file mode 100644 index 000000000000..7f06865f50d2 --- /dev/null +++ b/src/main/java/seedu/address/commons/events/ui/OverviewPanelChangedEvent.java @@ -0,0 +1,14 @@ +package seedu.address.commons.events.ui; + +import seedu.address.commons.events.BaseEvent; + +/** + * Represents a change in the Overview Panel + */ +public class OverviewPanelChangedEvent extends BaseEvent { + + @Override + public String toString() { + return getClass().getSimpleName(); + } +} diff --git a/src/main/java/seedu/address/commons/events/ui/OverviewPanelEventUpdateEvent.java b/src/main/java/seedu/address/commons/events/ui/OverviewPanelEventUpdateEvent.java new file mode 100644 index 000000000000..38b1dd6e68d2 --- /dev/null +++ b/src/main/java/seedu/address/commons/events/ui/OverviewPanelEventUpdateEvent.java @@ -0,0 +1,14 @@ +package seedu.address.commons.events.ui; + +import seedu.address.commons.events.BaseEvent; + +/** + * Represents an update to the events in Overview Panel + */ +public class OverviewPanelEventUpdateEvent extends BaseEvent { + + @Override + public String toString() { + return getClass().getSimpleName(); + } +} diff --git a/src/main/java/seedu/address/commons/events/ui/OverviewPanelVolunteerUpdateEvent.java b/src/main/java/seedu/address/commons/events/ui/OverviewPanelVolunteerUpdateEvent.java new file mode 100644 index 000000000000..fb57c3e15a7a --- /dev/null +++ b/src/main/java/seedu/address/commons/events/ui/OverviewPanelVolunteerUpdateEvent.java @@ -0,0 +1,14 @@ +package seedu.address.commons.events.ui; + +import seedu.address.commons.events.BaseEvent; + +/** + * Represents an update to the volunteers in Overview Panel + */ +public class OverviewPanelVolunteerUpdateEvent extends BaseEvent { + + @Override + public String toString() { + return getClass().getSimpleName(); + } +} diff --git a/src/main/java/seedu/address/commons/events/ui/PersonPanelSelectionChangedEvent.java b/src/main/java/seedu/address/commons/events/ui/PersonPanelSelectionChangedEvent.java deleted file mode 100644 index c5c8b9ce90ed..000000000000 --- a/src/main/java/seedu/address/commons/events/ui/PersonPanelSelectionChangedEvent.java +++ /dev/null @@ -1,26 +0,0 @@ -package seedu.address.commons.events.ui; - -import seedu.address.commons.events.BaseEvent; -import seedu.address.model.person.Person; - -/** - * Represents a selection change in the Person List Panel - */ -public class PersonPanelSelectionChangedEvent extends BaseEvent { - - - private final Person newSelection; - - public PersonPanelSelectionChangedEvent(Person newSelection) { - this.newSelection = newSelection; - } - - @Override - public String toString() { - return getClass().getSimpleName(); - } - - public Person getNewSelection() { - return newSelection; - } -} diff --git a/src/main/java/seedu/address/commons/events/ui/RecordChangeEvent.java b/src/main/java/seedu/address/commons/events/ui/RecordChangeEvent.java new file mode 100644 index 000000000000..4c1b4092c453 --- /dev/null +++ b/src/main/java/seedu/address/commons/events/ui/RecordChangeEvent.java @@ -0,0 +1,26 @@ +package seedu.address.commons.events.ui; + +import seedu.address.commons.events.BaseEvent; +import seedu.address.model.event.Event; + +/** + * Indicates a request to jump to the list of volunteers + */ +public class RecordChangeEvent extends BaseEvent { + + private final Event currentEvent; + + public RecordChangeEvent(Event newSelection) { + this.currentEvent = newSelection; + } + + public Event getCurrentEvent() { + return currentEvent; + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + +} diff --git a/src/main/java/seedu/address/commons/events/ui/ReplaceWithContextPanelEvent.java b/src/main/java/seedu/address/commons/events/ui/ReplaceWithContextPanelEvent.java new file mode 100644 index 000000000000..412eb6b41d07 --- /dev/null +++ b/src/main/java/seedu/address/commons/events/ui/ReplaceWithContextPanelEvent.java @@ -0,0 +1,14 @@ +package seedu.address.commons.events.ui; + +import seedu.address.commons.events.BaseEvent; + +/** + * Represents a change to current context panel. + */ +public class ReplaceWithContextPanelEvent extends BaseEvent { + + @Override + public String toString() { + return getClass().getSimpleName(); + } +} diff --git a/src/main/java/seedu/address/commons/events/ui/VolunteerPanelSelectionChangedEvent.java b/src/main/java/seedu/address/commons/events/ui/VolunteerPanelSelectionChangedEvent.java new file mode 100644 index 000000000000..10c54470f8f9 --- /dev/null +++ b/src/main/java/seedu/address/commons/events/ui/VolunteerPanelSelectionChangedEvent.java @@ -0,0 +1,26 @@ +package seedu.address.commons.events.ui; + +import seedu.address.commons.events.BaseEvent; +import seedu.address.model.volunteer.Volunteer; + +/** + * Represents a selection change in the Volunteer List Panel + */ +public class VolunteerPanelSelectionChangedEvent extends BaseEvent { + + + private final Volunteer newSelection; + + public VolunteerPanelSelectionChangedEvent(Volunteer newSelection) { + this.newSelection = newSelection; + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + + public Volunteer getNewSelection() { + return newSelection; + } +} diff --git a/src/main/java/seedu/address/commons/util/BirthdayUtil.java b/src/main/java/seedu/address/commons/util/BirthdayUtil.java new file mode 100644 index 000000000000..d9ebe8638212 --- /dev/null +++ b/src/main/java/seedu/address/commons/util/BirthdayUtil.java @@ -0,0 +1,26 @@ +package seedu.address.commons.util; + +import java.text.ParseException; +import java.text.SimpleDateFormat; + +import seedu.address.model.volunteer.Birthday; + +/** + * Utility methods related to Birthday + */ +public class BirthdayUtil { + + /** + * Returns a friendly date string of a Volunteer Birthday object. + */ + public static String getFriendlyDateFromVolunteerBirthday(Birthday birthday) { + SimpleDateFormat inf = new SimpleDateFormat("dd-MM-yyyy"); + SimpleDateFormat outf = new SimpleDateFormat("d MMMMM yyyy"); + + try { + return outf.format(inf.parse(birthday.value)); + } catch (ParseException e) { + return birthday.value; + } + } +} diff --git a/src/main/java/seedu/address/commons/util/DateTimeUtil.java b/src/main/java/seedu/address/commons/util/DateTimeUtil.java new file mode 100644 index 000000000000..1ec5c399a1a0 --- /dev/null +++ b/src/main/java/seedu/address/commons/util/DateTimeUtil.java @@ -0,0 +1,69 @@ +package seedu.address.commons.util; + +import java.text.ParseException; +import java.text.SimpleDateFormat; + +import seedu.address.model.event.Date; +import seedu.address.model.event.Time; + +/** + * Utility methods related to Date + */ +public class DateTimeUtil { + + public static final int UPCOMING_EVENT = 0; + public static final int ONGOING_EVENT = 1; + public static final int COMPLETED_EVENT = 2; + public static final int INVALID_STATUS = 3; + + public static final String[] STATUS = { "Upcoming", "Ongoing", "Completed" }; + + /** + * Returns a friendly date string of an Event Date object. + */ + public static String getFriendlyDateFromEventDate(Date date) { + SimpleDateFormat inf = new SimpleDateFormat("dd-MM-yyyy"); + SimpleDateFormat outf = new SimpleDateFormat("EEE, d MMM yy"); + + try { + return outf.format(inf.parse(date.value)); + } catch (ParseException e) { + return date.value; + } + } + + /** + * Returns a friendly time string of an Event Time object. + */ + public static String getFriendlyTimeFromEventTime(Time time) { + SimpleDateFormat inf = new SimpleDateFormat("HH:mm"); + SimpleDateFormat outf = new SimpleDateFormat("K:mma"); + + try { + return outf.format(inf.parse(time.value)); + } catch (ParseException e) { + return time.value; + } + } + + public static int getEventStatus(Date startDate, Time startTime, Date endDate, Time endTime) { + SimpleDateFormat inf = new SimpleDateFormat("dd-MM-yyyy HH:mm"); + + try { + java.util.Date start = inf.parse(startDate + " " + startTime); + java.util.Date end = inf.parse(endDate + " " + endTime); + java.util.Date now = new java.util.Date(); + + if (now.compareTo(start) < 0) { + return UPCOMING_EVENT; + } else if (now.compareTo(start) >= 0 && now.compareTo(end) <= 0) { + return ONGOING_EVENT; + } else { + return COMPLETED_EVENT; + } + + } catch (ParseException e) { + return INVALID_STATUS; + } + } +} diff --git a/src/main/java/seedu/address/commons/util/GenderUtil.java b/src/main/java/seedu/address/commons/util/GenderUtil.java new file mode 100644 index 000000000000..8373992ac2cc --- /dev/null +++ b/src/main/java/seedu/address/commons/util/GenderUtil.java @@ -0,0 +1,26 @@ +package seedu.address.commons.util; + +import seedu.address.model.volunteer.Gender; + +/** + * Utility methods related to Gender + */ +public class GenderUtil { + public static final String GENDER_MALE_VALIDATION_REGEX = "m"; + public static final String GENDER_FEMALE_VALIDATION_REGEX = "f"; + public static final String GENDER_MALE_FORMAT = "Male"; + public static final String GENDER_FEMALE_FORMAT = "Female"; + + private static String formattedGender; + /** + * Returns a friendly date string of a Volunteer Birthday object. + */ + public static String getFriendlyGenderFromVolunteerGender(Gender gender) { + if (gender.value.equals(GENDER_FEMALE_VALIDATION_REGEX)) { + formattedGender = GENDER_FEMALE_FORMAT; + } else if (gender.value.equals(GENDER_MALE_VALIDATION_REGEX)) { + formattedGender = GENDER_MALE_FORMAT; + } + return formattedGender; + } +} diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java index 8b34b862039a..988552c7fb6c 100644 --- a/src/main/java/seedu/address/logic/Logic.java +++ b/src/main/java/seedu/address/logic/Logic.java @@ -4,7 +4,9 @@ import seedu.address.logic.commands.CommandResult; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.Person; +import seedu.address.model.event.Event; +import seedu.address.model.record.Record; +import seedu.address.model.volunteer.Volunteer; /** * API of the Logic component @@ -18,10 +20,18 @@ public interface Logic { * @throws ParseException If an error occurs during parsing. */ CommandResult execute(String commandText) throws CommandException, ParseException; + /** Returns an unmodifiable view of the filtered list of volunteers */ + ObservableList getFilteredVolunteerList(); - /** Returns an unmodifiable view of the filtered list of persons */ - ObservableList getFilteredPersonList(); + /** Returns an unmodifiable view of the filtered list of events */ + ObservableList getFilteredEventList(); + + /** Returns an unmodifiable view of the filtered list of events */ + ObservableList getFilteredRecordList(); /** Returns the list of input entered by the user, encapsulated in a {@code ListElementPointer} object */ ListElementPointer getHistorySnapshot(); + + /** Returns the context id */ + String getContextId(); } diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java index 9aff86fc33dc..617c99de1ad8 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/seedu/address/logic/LogicManager.java @@ -11,7 +11,9 @@ import seedu.address.logic.parser.AddressBookParser; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.Model; -import seedu.address.model.person.Person; +import seedu.address.model.event.Event; +import seedu.address.model.record.Record; +import seedu.address.model.volunteer.Volunteer; /** * The main LogicManager of the app. @@ -33,7 +35,7 @@ public LogicManager(Model model) { public CommandResult execute(String commandText) throws CommandException, ParseException { logger.info("----------------[USER COMMAND][" + commandText + "]"); try { - Command command = addressBookParser.parseCommand(commandText); + Command command = addressBookParser.parseCommand(commandText, model.getContextId()); return command.execute(model, history); } finally { history.add(commandText); @@ -41,12 +43,27 @@ public CommandResult execute(String commandText) throws CommandException, ParseE } @Override - public ObservableList getFilteredPersonList() { - return model.getFilteredPersonList(); + public ObservableList getFilteredVolunteerList() { + return model.getFilteredVolunteerList(); + } + + @Override + public ObservableList getFilteredEventList() { + return model.getFilteredEventList(); + } + + @Override + public ObservableList getFilteredRecordList() { + return model.getFilteredRecordList(); } @Override public ListElementPointer getHistorySnapshot() { return new ListElementPointer(history.getHistory()); } + + @Override + public String getContextId() { + return model.getContextId(); + } } diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java index d88e831ff1ce..a7e087934005 100644 --- a/src/main/java/seedu/address/logic/commands/AddCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddCommand.java @@ -2,61 +2,73 @@ import static java.util.Objects.requireNonNull; import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_BIRTHDAY; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_GENDER; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ID; 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.core.EventsCenter; +import seedu.address.commons.events.ui.OverviewPanelVolunteerUpdateEvent; import seedu.address.logic.CommandHistory; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; -import seedu.address.model.person.Person; +import seedu.address.model.volunteer.Volunteer; /** - * Adds a person to the address book. + * Adds a volunteer to the application. */ 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 MESSAGE_USAGE = COMMAND_WORD + ": Adds a volunteer to the application. " + "Parameters: " + PREFIX_NAME + "NAME " + + PREFIX_ID + "NRIC " + + PREFIX_GENDER + "GENDER " + + PREFIX_BIRTHDAY + "BIRTHDAY " + PREFIX_PHONE + "PHONE " + PREFIX_EMAIL + "EMAIL " + PREFIX_ADDRESS + "ADDRESS " + "[" + PREFIX_TAG + "TAG]...\n" + "Example: " + COMMAND_WORD + " " + PREFIX_NAME + "John Doe " + + PREFIX_ID + "S8512345A " + + PREFIX_GENDER + "m " + + PREFIX_BIRTHDAY + "01-10-1985 " + PREFIX_PHONE + "98765432 " + PREFIX_EMAIL + "johnd@example.com " + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 " + PREFIX_TAG + "friends " - + PREFIX_TAG + "owesMoney"; + + PREFIX_TAG + "driver"; - 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 volunteer added: %1$s"; + public static final String MESSAGE_DUPLICATE_VOLUNTEER = "This volunteer already exists in the application."; - private final Person toAdd; + private final Volunteer toAdd; /** - * Creates an AddCommand to add the specified {@code Person} + * Creates an AddCommand to add the specified {@code Volunteer} */ - public AddCommand(Person person) { - requireNonNull(person); - toAdd = person; + public AddCommand(Volunteer volunteer) { + requireNonNull(volunteer); + toAdd = volunteer; } @Override public CommandResult execute(Model model, CommandHistory history) throws CommandException { requireNonNull(model); - if (model.hasPerson(toAdd)) { - throw new CommandException(MESSAGE_DUPLICATE_PERSON); + if (model.hasVolunteer(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_VOLUNTEER); } - model.addPerson(toAdd); + model.addVolunteer(toAdd); model.commitAddressBook(); + EventsCenter.getInstance().post(new OverviewPanelVolunteerUpdateEvent()); return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); } diff --git a/src/main/java/seedu/address/logic/commands/AddEventCommand.java b/src/main/java/seedu/address/logic/commands/AddEventCommand.java new file mode 100644 index 000000000000..6a93d45fc07f --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/AddEventCommand.java @@ -0,0 +1,80 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_DESCRIPTION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_END_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_END_TIME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_LOCATION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_START_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_START_TIME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; + +import seedu.address.commons.core.EventsCenter; +import seedu.address.commons.events.ui.OverviewPanelEventUpdateEvent; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.event.Event; + +/** + * Adds an event to the application. + */ +public class AddEventCommand extends Command { + + public static final String COMMAND_WORD = "add"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds an event record to the application. " + + "Parameters: " + + PREFIX_EVENT_NAME + "NAME " + + PREFIX_EVENT_LOCATION + "LOCATION " + + PREFIX_EVENT_START_DATE + "START DATE " + + PREFIX_EVENT_END_DATE + "END DATE " + + PREFIX_EVENT_START_TIME + "START TIME " + + PREFIX_EVENT_END_TIME + "END TIME " + + PREFIX_EVENT_DESCRIPTION + "DESCRIPTION " + + "[" + PREFIX_TAG + "TAG]...\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_EVENT_NAME + "Youth Humanitarian Challenge " + + PREFIX_EVENT_LOCATION + "29 Havelock Road " + + PREFIX_EVENT_START_DATE + "28-09-2018 " + + PREFIX_EVENT_END_DATE + "28-09-2018 " + + PREFIX_EVENT_START_TIME + "10:00 " + + PREFIX_EVENT_END_TIME + "14:00 " + + PREFIX_EVENT_DESCRIPTION + "To engage youths in humanitarianism. " + + PREFIX_TAG + "Competition "; + + public static final String MESSAGE_SUCCESS = "New event added: %1$s"; + public static final String MESSAGE_DUPLICATE_EVENT = "This event already exists."; + + private final Event toAdd; + + /** + * Creates an AddEventCommand to add the specified {@code Event} + */ + public AddEventCommand(Event event) { + requireNonNull(event); + toAdd = event; + } + + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + requireNonNull(model); + + if (model.hasEvent(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_EVENT); + } + + model.addEvent(toAdd); + model.commitAddressBook(); + EventsCenter.getInstance().post(new OverviewPanelEventUpdateEvent()); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddEventCommand // instanceof handles nulls + && toAdd.equals(((AddEventCommand) other).toAdd)); + } +} diff --git a/src/main/java/seedu/address/logic/commands/AddRecordCommand.java b/src/main/java/seedu/address/logic/commands/AddRecordCommand.java new file mode 100644 index 000000000000..4b68da02ce0e --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/AddRecordCommand.java @@ -0,0 +1,89 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_RECORD_HOUR; +import static seedu.address.logic.parser.CliSyntax.PREFIX_RECORD_REMARK; + +import java.util.List; + +import seedu.address.commons.core.EventsCenter; +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.commons.events.ui.ContextChangeEvent; +import seedu.address.commons.events.ui.RecordChangeEvent; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.record.Record; +import seedu.address.model.record.RecordContainsEventIdPredicate; +import seedu.address.model.volunteer.Volunteer; + +/** + * Adds a record to the application. + */ +public class AddRecordCommand extends Command { + + public static final String COMMAND_WORD = "add"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a volunteer record to the event that " + + "is currently managed." + + "Parameters: VOLUNTEER_INDEX (must be a positive integer) " + + "[" + PREFIX_RECORD_HOUR + "HOURS] " + + "[" + PREFIX_RECORD_REMARK + "REMARKS]\n" + + "Example: " + COMMAND_WORD + " " + + "1 " + + PREFIX_RECORD_HOUR + "5 " + + PREFIX_RECORD_REMARK + "Emcee"; + + public static final String MESSAGE_SUCCESS = "Record added: %1$s"; + public static final String MESSAGE_DUPLICATE_RECORD = "This volunteer is already registered."; + + public final Index index; + private final Record toAdd; + + /** + * Creates an AddCommand to add the specified {@code Person} + */ + public AddRecordCommand(Index index, Record record) { + requireNonNull(index); + requireNonNull(record); + this.index = index; + this.toAdd = record; + } + + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + requireNonNull(model); + + List lastShownList = model.getFilteredVolunteerList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_VOLUNTEER_DISPLAYED_INDEX); + } + + Volunteer volunteerSelected = lastShownList.get(index.getZeroBased()); + Record record = new Record(model.getSelectedEvent().getEventId(), volunteerSelected.getVolunteerId(), + toAdd.getHour(), toAdd.getRemark()); + record.setVolunteerName(volunteerSelected.getName().fullName); + + if (model.hasRecord(record)) { + throw new CommandException(MESSAGE_DUPLICATE_RECORD); + } + + model.addRecord(record); + model.updateFilteredRecordList(new RecordContainsEventIdPredicate(model.getSelectedEvent().getEventId())); + model.commitAddressBook(); + + // Posting event + EventsCenter.getInstance().post(new RecordChangeEvent(model.getSelectedEvent())); + EventsCenter.getInstance().post(new ContextChangeEvent(model.getContextId())); + return new CommandResult(String.format(MESSAGE_SUCCESS, record)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddRecordCommand // instanceof handles nulls + && toAdd.equals(((AddRecordCommand) other).toAdd)); + } +} diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java index 1f85bcfe85a8..fd999adbf96d 100644 --- a/src/main/java/seedu/address/logic/commands/ClearCommand.java +++ b/src/main/java/seedu/address/logic/commands/ClearCommand.java @@ -7,12 +7,12 @@ import seedu.address.model.Model; /** - * Clears the address book. + * Clears the data from the application. */ 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 = "SocialCare data has been cleared!"; @Override diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java index a20e9d49eac7..888b5b55bc94 100644 --- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java +++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java @@ -2,28 +2,33 @@ import static java.util.Objects.requireNonNull; +import java.util.ArrayList; import java.util.List; +import seedu.address.commons.core.EventsCenter; import seedu.address.commons.core.Messages; import seedu.address.commons.core.index.Index; +import seedu.address.commons.events.ui.OverviewPanelVolunteerUpdateEvent; import seedu.address.logic.CommandHistory; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; -import seedu.address.model.person.Person; +import seedu.address.model.record.Record; +import seedu.address.model.record.RecordContainsVolunteerIdPredicate; +import seedu.address.model.volunteer.Volunteer; /** - * Deletes a person identified using it's displayed index from the address book. + * Deletes a volunteer identified using it's displayed index from the application. */ public class DeleteCommand extends Command { public static final String COMMAND_WORD = "delete"; public static final String MESSAGE_USAGE = COMMAND_WORD - + ": Deletes the person identified by the index number used in the displayed person list.\n" + + ": Deletes the volunteer identified by the index number used in the displayed volunteer list.\n" + "Parameters: INDEX (must be a positive integer)\n" + "Example: " + COMMAND_WORD + " 1"; - public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s"; + public static final String MESSAGE_DELETE_VOLUNTEER_SUCCESS = "Deleted Volunteer: %1$s"; private final Index targetIndex; @@ -34,16 +39,26 @@ public DeleteCommand(Index targetIndex) { @Override public CommandResult execute(Model model, CommandHistory history) throws CommandException { requireNonNull(model); - List lastShownList = model.getFilteredPersonList(); + List lastShownList = model.getFilteredVolunteerList(); if (targetIndex.getZeroBased() >= lastShownList.size()) { - throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + throw new CommandException(Messages.MESSAGE_INVALID_VOLUNTEER_DISPLAYED_INDEX); + } + + Volunteer volunteerToDelete = lastShownList.get(targetIndex.getZeroBased()); + model.deleteVolunteer(volunteerToDelete); + + model.updateFilteredRecordList(new RecordContainsVolunteerIdPredicate(volunteerToDelete.getVolunteerId())); + List recordList = new ArrayList<>(); + recordList.addAll(model.getFilteredRecordList()); + + for (Record r : recordList) { + model.deleteRecord(r); } - Person personToDelete = lastShownList.get(targetIndex.getZeroBased()); - model.deletePerson(personToDelete); model.commitAddressBook(); - return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete)); + EventsCenter.getInstance().post(new OverviewPanelVolunteerUpdateEvent()); + return new CommandResult(String.format(MESSAGE_DELETE_VOLUNTEER_SUCCESS, volunteerToDelete)); } @Override diff --git a/src/main/java/seedu/address/logic/commands/DeleteEventCommand.java b/src/main/java/seedu/address/logic/commands/DeleteEventCommand.java new file mode 100644 index 000000000000..760f16126d7d --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/DeleteEventCommand.java @@ -0,0 +1,69 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.ArrayList; +import java.util.List; + +import seedu.address.commons.core.EventsCenter; +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.commons.events.ui.OverviewPanelEventUpdateEvent; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.event.Event; +import seedu.address.model.record.Record; +import seedu.address.model.record.RecordContainsEventIdPredicate; + +/** + * Deletes an event identified using it's displayed index from the application. + */ +public class DeleteEventCommand extends Command { + public static final String COMMAND_WORD = "delete"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes the event identified by the index number used in the displayed event list.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_DELETE_EVENT_SUCCESS = "Deleted Event: %1$s"; + + private final Index targetIndex; + + public DeleteEventCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredEventList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_EVENT_DISPLAYED_INDEX); + } + + Event eventToDelete = lastShownList.get(targetIndex.getZeroBased()); + model.deleteEvent(eventToDelete); + + model.updateFilteredRecordList(new RecordContainsEventIdPredicate(eventToDelete.getEventId())); + List recordList = new ArrayList<>(); + recordList.addAll(model.getFilteredRecordList()); + + for (Record r : recordList) { + model.deleteRecord(r); + } + + model.commitAddressBook(); + EventsCenter.getInstance().post(new OverviewPanelEventUpdateEvent()); + return new CommandResult(String.format(MESSAGE_DELETE_EVENT_SUCCESS, eventToDelete)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof DeleteEventCommand // instanceof handles nulls + && targetIndex.equals(((DeleteEventCommand) other).targetIndex)); // state check + } +} diff --git a/src/main/java/seedu/address/logic/commands/DeleteRecordCommand.java b/src/main/java/seedu/address/logic/commands/DeleteRecordCommand.java new file mode 100644 index 000000000000..583d1e5bcac9 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/DeleteRecordCommand.java @@ -0,0 +1,58 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; + +import java.util.List; + +import seedu.address.commons.core.EventsCenter; +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.commons.events.ui.RecordChangeEvent; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.record.Record; + +/** + * Deletes a record identified using it's displayed index from the application. + */ +public class DeleteRecordCommand extends Command { + + public static final String COMMAND_WORD = "delete"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes the record identified by the index number used in the displayed records panel.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_DELETE_RECORD_SUCCESS = "Deleted record: %1$s"; + + private final Index targetIndex; + + public DeleteRecordCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredRecordList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_RECORD_DISPLAYED_INDEX); + } + + Record recordToDelete = lastShownList.get(targetIndex.getZeroBased()); + model.deleteRecord(recordToDelete); + model.commitAddressBook(); + EventsCenter.getInstance().post(new RecordChangeEvent(model.getSelectedEvent())); + return new CommandResult(String.format(MESSAGE_DELETE_RECORD_SUCCESS, recordToDelete)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof DeleteRecordCommand // instanceof handles nulls + && targetIndex.equals(((DeleteRecordCommand) other).targetIndex)); // state check + } +} diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index dc782d8e230f..254d53746448 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -2,11 +2,13 @@ import static java.util.Objects.requireNonNull; import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_BIRTHDAY; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_GENDER; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; -import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_VOLUNTEERS; import java.util.Collections; import java.util.HashSet; @@ -14,31 +16,39 @@ import java.util.Optional; import java.util.Set; +import seedu.address.commons.core.EventsCenter; import seedu.address.commons.core.Messages; import seedu.address.commons.core.index.Index; +import seedu.address.commons.events.ui.OverviewPanelVolunteerUpdateEvent; import seedu.address.commons.util.CollectionUtil; import seedu.address.logic.CommandHistory; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Person; -import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +import seedu.address.model.volunteer.Address; +import seedu.address.model.volunteer.Birthday; +import seedu.address.model.volunteer.Email; +import seedu.address.model.volunteer.Gender; +import seedu.address.model.volunteer.Name; +import seedu.address.model.volunteer.Phone; +import seedu.address.model.volunteer.Volunteer; +import seedu.address.model.volunteer.VolunteerId; /** - * Edits the details of an existing person in the address book. + * Edits the details of an existing volunteer in the application. */ 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 volunteer identified " + + "by the index number used in the displayed volunteer list. " + + "NRIC numbers are not editable. " + "Existing values will be overwritten by the input values.\n" + "Parameters: INDEX (must be a positive integer) " + "[" + PREFIX_NAME + "NAME] " + + "[" + PREFIX_GENDER + "GENDER] " + + "[" + PREFIX_BIRTHDAY + "BIRTHDAY] " + "[" + PREFIX_PHONE + "PHONE] " + "[" + PREFIX_EMAIL + "EMAIL] " + "[" + PREFIX_ADDRESS + "ADDRESS] " @@ -47,61 +57,67 @@ public class EditCommand extends Command { + 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_VOLUNTEER_SUCCESS = "Edited Volunteer: %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_VOLUNTEER = "This volunteer already exists in the application."; private final Index index; - private final EditPersonDescriptor editPersonDescriptor; + private final EditVolunteerDescriptor editVolunteerDescriptor; /** - * @param index of the person in the filtered person list to edit - * @param editPersonDescriptor details to edit the person with + * @param index of the volunteer in the filtered volunteer list to edit + * @param editVolunteerDescriptor details to edit the volunteer with */ - public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) { + public EditCommand(Index index, EditVolunteerDescriptor editVolunteerDescriptor) { requireNonNull(index); - requireNonNull(editPersonDescriptor); + requireNonNull(editVolunteerDescriptor); this.index = index; - this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor); + this.editVolunteerDescriptor = new EditVolunteerDescriptor(editVolunteerDescriptor); } @Override public CommandResult execute(Model model, CommandHistory history) throws CommandException { requireNonNull(model); - List lastShownList = model.getFilteredPersonList(); + List lastShownList = model.getFilteredVolunteerList(); if (index.getZeroBased() >= lastShownList.size()) { - throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + throw new CommandException(Messages.MESSAGE_INVALID_VOLUNTEER_DISPLAYED_INDEX); } - Person personToEdit = lastShownList.get(index.getZeroBased()); - Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor); + Volunteer volunteerToEdit = lastShownList.get(index.getZeroBased()); + Volunteer editedVolunteer = createEditedVolunteer(volunteerToEdit, editVolunteerDescriptor); - if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) { - throw new CommandException(MESSAGE_DUPLICATE_PERSON); + if (!volunteerToEdit.isSameVolunteer(editedVolunteer) && model.hasVolunteer(editedVolunteer)) { + throw new CommandException(MESSAGE_DUPLICATE_VOLUNTEER); } - model.updatePerson(personToEdit, editedPerson); - model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + model.updateVolunteer(volunteerToEdit, editedVolunteer); + model.updateFilteredVolunteerList(PREDICATE_SHOW_ALL_VOLUNTEERS); model.commitAddressBook(); - return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson)); + EventsCenter.getInstance().post(new OverviewPanelVolunteerUpdateEvent()); + return new CommandResult(String.format(MESSAGE_EDIT_VOLUNTEER_SUCCESS, editedVolunteer)); } /** - * Creates and returns a {@code Person} with the details of {@code personToEdit} - * edited with {@code editPersonDescriptor}. + * Creates and returns a {@code Volunteer} with the details of {@code volunteerToEdit} + * edited with {@code editVolunteerDescriptor}. */ - private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) { - assert personToEdit != null; - - Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName()); - Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone()); - Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail()); - Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress()); - Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags()); - - return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags); + private static Volunteer createEditedVolunteer(Volunteer volunteerToEdit, + EditVolunteerDescriptor editVolunteerDescriptor) { + assert volunteerToEdit != null; + + Name updatedName = editVolunteerDescriptor.getName().orElse(volunteerToEdit.getName()); + VolunteerId updatedVolunteerId = volunteerToEdit.getVolunteerId(); + Gender updatedGender = editVolunteerDescriptor.getGender().orElse(volunteerToEdit.getGender()); + Birthday updatedBirthday = editVolunteerDescriptor.getBirthday().orElse(volunteerToEdit.getBirthday()); + Phone updatedPhone = editVolunteerDescriptor.getPhone().orElse(volunteerToEdit.getPhone()); + Email updatedEmail = editVolunteerDescriptor.getEmail().orElse(volunteerToEdit.getEmail()); + Address updatedAddress = editVolunteerDescriptor.getAddress().orElse(volunteerToEdit.getAddress()); + Set updatedTags = editVolunteerDescriptor.getTags().orElse(volunteerToEdit.getTags()); + + return new Volunteer(updatedName, updatedVolunteerId, updatedGender, updatedBirthday, + updatedPhone, updatedEmail, updatedAddress, updatedTags); } @Override @@ -119,28 +135,32 @@ public boolean equals(Object other) { // state check EditCommand e = (EditCommand) other; return index.equals(e.index) - && editPersonDescriptor.equals(e.editPersonDescriptor); + && editVolunteerDescriptor.equals(e.editVolunteerDescriptor); } /** - * Stores the details to edit the person with. Each non-empty field value will replace the - * corresponding field value of the person. + * Stores the details to edit the volunteer with. Each non-empty field value will replace the + * corresponding field value of the volunteer. */ - public static class EditPersonDescriptor { + public static class EditVolunteerDescriptor { private Name name; + private Gender gender; + private Birthday birthday; private Phone phone; private Email email; private Address address; private Set tags; - public EditPersonDescriptor() {} + public EditVolunteerDescriptor() {} /** * Copy constructor. * A defensive copy of {@code tags} is used internally. */ - public EditPersonDescriptor(EditPersonDescriptor toCopy) { + public EditVolunteerDescriptor(EditVolunteerDescriptor toCopy) { setName(toCopy.name); + setGender(toCopy.gender); + setBirthday(toCopy.birthday); setPhone(toCopy.phone); setEmail(toCopy.email); setAddress(toCopy.address); @@ -151,7 +171,7 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) { * Returns true if at least one field is edited. */ public boolean isAnyFieldEdited() { - return CollectionUtil.isAnyNonNull(name, phone, email, address, tags); + return CollectionUtil.isAnyNonNull(name, gender, birthday, phone, email, address, tags); } public void setName(Name name) { @@ -162,6 +182,22 @@ public Optional getName() { return Optional.ofNullable(name); } + public void setGender(Gender gender) { + this.gender = gender; + } + + public Optional getGender() { + return Optional.ofNullable(gender); + } + + public void setBirthday(Birthday birthday) { + this.birthday = birthday; + } + + public Optional getBirthday() { + return Optional.ofNullable(birthday); + } + public void setPhone(Phone phone) { this.phone = phone; } @@ -211,14 +247,16 @@ public boolean equals(Object other) { } // instanceof handles nulls - if (!(other instanceof EditPersonDescriptor)) { + if (!(other instanceof EditVolunteerDescriptor)) { return false; } // state check - EditPersonDescriptor e = (EditPersonDescriptor) other; + EditVolunteerDescriptor e = (EditVolunteerDescriptor) other; return getName().equals(e.getName()) + && getGender().equals(e.getGender()) + && getBirthday().equals(e.getBirthday()) && getPhone().equals(e.getPhone()) && getEmail().equals(e.getEmail()) && getAddress().equals(e.getAddress()) diff --git a/src/main/java/seedu/address/logic/commands/EditEventCommand.java b/src/main/java/seedu/address/logic/commands/EditEventCommand.java new file mode 100644 index 000000000000..9955900a1b14 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/EditEventCommand.java @@ -0,0 +1,279 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_DESCRIPTION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_END_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_END_TIME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_LOCATION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_START_DATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_START_TIME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_EVENTS; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import seedu.address.commons.core.EventsCenter; +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.commons.events.ui.OverviewPanelEventUpdateEvent; +import seedu.address.commons.util.CollectionUtil; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.event.Date; +import seedu.address.model.event.Description; +import seedu.address.model.event.Event; +import seedu.address.model.event.EventId; +import seedu.address.model.event.Location; +import seedu.address.model.event.Name; +import seedu.address.model.event.Time; +import seedu.address.model.tag.Tag; + +/** + * Edits the details of an existing event in the application. + */ +public class EditEventCommand extends Command { + + public static final String COMMAND_WORD = "edit"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the event identified " + + "by the index number used in the displayed event list. " + + "Existing values will be overwritten by the input values.\n" + + "Parameters: INDEX (must be a positive integer) " + + "[" + PREFIX_EVENT_NAME + "NAME] " + + "[" + PREFIX_EVENT_LOCATION + "LOCATION] " + + "[" + PREFIX_EVENT_START_DATE + "START DATE] " + + "[" + PREFIX_EVENT_END_DATE + "END DATE] " + + "[" + PREFIX_EVENT_START_TIME + "START TIME] " + + "[" + PREFIX_EVENT_END_TIME + "END TIME] " + + "[" + PREFIX_EVENT_DESCRIPTION + "DESCRIPTION] " + + "[" + PREFIX_TAG + "TAG]...\n" + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_EVENT_LOCATION + "25, Tannery Lane #01-27 " + + PREFIX_EVENT_DESCRIPTION + "Charity drive"; + + public static final String MESSAGE_EDIT_EVENT_SUCCESS = "Edited Event: %1$s"; + public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided."; + public static final String MESSAGE_DUPLICATE_EVENT = "This event already exists."; + + private final Index index; + private final EditEventDescriptor editEventDescriptor; + + /** + * @param index of the event in the filtered event list to edit + * @param editEventDescriptor details to edit the event with + */ + public EditEventCommand(Index index, EditEventDescriptor editEventDescriptor) { + requireNonNull(index); + requireNonNull(editEventDescriptor); + + this.index = index; + this.editEventDescriptor = new EditEventDescriptor(editEventDescriptor); + } + + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredEventList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_EVENT_DISPLAYED_INDEX); + } + + Event eventToEdit = lastShownList.get(index.getZeroBased()); + Event editedEvent = createEditedEvent(eventToEdit, editEventDescriptor); + + if (!eventToEdit.isSameEvent(editedEvent) && model.hasEvent(editedEvent)) { + throw new CommandException(MESSAGE_DUPLICATE_EVENT); + } + + model.updateEvent(eventToEdit, editedEvent); + model.updateFilteredEventList(PREDICATE_SHOW_ALL_EVENTS); + model.commitAddressBook(); + EventsCenter.getInstance().post(new OverviewPanelEventUpdateEvent()); + return new CommandResult(String.format(MESSAGE_EDIT_EVENT_SUCCESS, editedEvent)); + } + + /** + * Creates and returns an {@code Event} with the details of {@code eventToEdit} + * edited with {@code editEventDescriptor}. + */ + private static Event createEditedEvent(Event eventToEdit, EditEventDescriptor editEventDescriptor) + throws CommandException { + assert eventToEdit != null; + + EventId eventId = eventToEdit.getEventId(); + Name updatedName = editEventDescriptor.getName().orElse(eventToEdit.getName()); + Location updatedLocation = editEventDescriptor.getLocation().orElse(eventToEdit.getLocation()); + + Date updatedStartDate = editEventDescriptor.getStartDate().orElse(eventToEdit.getStartDate()); + Date updatedEndDate = editEventDescriptor.getEndDate().orElse(eventToEdit.getEndDate()); + + if (!updatedStartDate.isLessThanOrEqualTo(updatedEndDate)) { + throw new CommandException(Event.MESSAGE_START_END_DATE_CONSTRAINTS); + } + + Time updatedStartTime = editEventDescriptor.getStartTime().orElse(eventToEdit.getStartTime()); + Time updatedEndTime = editEventDescriptor.getEndTime().orElse(eventToEdit.getEndTime()); + + if (!updatedStartTime.isLessThanOrEqualTo(updatedEndTime)) { + throw new CommandException(Event.MESSAGE_START_END_TIME_CONSTRAINTS); + } + + Description updatedDescription = editEventDescriptor.getDescription().orElse(eventToEdit.getDescription()); + Set updatedTags = editEventDescriptor.getTags().orElse(eventToEdit.getTags()); + + return new Event(eventId, updatedName, updatedLocation, updatedStartDate, updatedEndDate, updatedStartTime, + updatedEndTime, updatedDescription, updatedTags); + } + + /** + * Stores the details to edit the event with. Each non-empty field value will replace the + * corresponding field value of the event. + */ + public static class EditEventDescriptor { + private EventId eventId; + private Name name; + private Location location; + private Date startDate; + private Date endDate; + private Time startTime; + private Time endTime; + private Description description; + private Set tags; + + public EditEventDescriptor() {} + + /** + * Copy constructor. + * A defensive copy of {@code tags} is used internally. + */ + public EditEventDescriptor(EditEventDescriptor toCopy) { + setEventId(toCopy.eventId); + setName(toCopy.name); + setLocation(toCopy.location); + setStartDate(toCopy.startDate); + setEndDate(toCopy.endDate); + setStartTime(toCopy.startTime); + setEndTime(toCopy.endTime); + setDescription(toCopy.description); + setTags(toCopy.tags); + } + + /** + * Returns true if at least one field is edited. + */ + public boolean isAnyFieldEdited() { + return CollectionUtil.isAnyNonNull(name, location, startDate, endDate, startTime, endTime, + description, tags); + } + + public void setEventId(EventId eventId) { + this.eventId = eventId; + } + + public void setName(Name name) { + this.name = name; + } + + public Optional getName() { + return Optional.ofNullable(name); + } + + public void setLocation(Location location) { + this.location = location; + } + + public Optional getLocation() { + return Optional.ofNullable(location); + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Optional getStartDate() { + return Optional.ofNullable(startDate); + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + public Optional getEndDate() { + return Optional.ofNullable(endDate); + } + + public void setStartTime(Time startTime) { + this.startTime = startTime; + } + + public Optional