PROJECT: Coupon Stash


Overview

Coupon Stash is a desktop coupons manager that allows users to keep track of their coupons. The user interacts with it using a CLI, and it has a beautiful GUI created with JavaFX. It is written in Java, and has about 15kLoC.

Summary of contributions

  • Major enhancement: added the ability to use a coupon (Pull request #80, #98)

    • What it does: allows the user to keep track of his usage for each and every coupon.

    • Justification: This feature is essential in keeping track of coupons and also its generated savings.

    • Highlights: This enhancement ties in with other coupon fields to ensure the valid usage of a coupon. From the start date of the coupon, to the type of savings generated, this feature is critical to the functioning of Coupon Stash.

  • Major enhancement: added archiving mechanism (Pull Request #137)

    • What it does: automatically archive the coupon when it has expired or exhausted its usages.

    • Justification: This feature declutters the user’s visible list of active coupons, while retaining the ability to access the archived coupons if needed.

    • Highlights: Considerations were made on the design of the archiving system, where the initial phase focused on two separate data files for active and archived coupons. This was found to be highly coupled, and would increase complexity and maintainability of the application. This enhancement ties in with the Used and Expiring functionality of Coupons to ensure correct archiving of coupons.

  • Minor enhancement: Added shortcut (Ctrl + Q) to quit windows that do not have a CLI in Coupon Stash (e.g. Coupon, Remind Window), to maintain the ability to use Coupon Stash with only a keyboard (except scrolling of lists). (Pull Request #323)

  • Code contributed: [Functional & Test Code]

  • Other contributions:

    • UI Lead:

      • Drafted and designed the overall User Interface and Logo of Coupon Stash (link)

      • Created Coupon, Coupon Window, and Remind Window base FXML code (Pull Request #170, #300, #317, #328)

    • Project management:

      • Lead the project in terms of direction of product, defining and assigning tasks.

    • Documentation:

      • Added Use Cases in User Guide (Pull Request #28)

      • Edit various part of User Guide (Pull request #148)

    • Community:

      • PRs reviewed (with non-trivial review comments): #110, #115, #154

      • Reported bugs and suggestions for other teams in the class (examples: 1, 2, 3)

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.

Using a coupon: used

Use a coupon if its usage has yet to reach its limit. Requires an original amount of purchase if the coupon has savings in a percentage value.

Format: used INDEX or used INDEX MONETARY_AMOUNT where MONETARY_AMOUNT is a number prefixed by a user-defined currency symbol e.g. ($4.50, where the currency symbol is "$").

  • Uses the coupon at the specified INDEX.

Examples:

  • used 1
    Uses the first coupon in the coupon list.

  • used 1 $10.0
    Uses the first coupon in the coupon list, which also has a percentage savings. The total savings of the coupon will be calculated, and can be seen with the command saved.

A coupon cannot be used if it has not reached its start date, or it is archived. If there is an intention to use the coupon, you can edit the start date or unarchive the coupon.

Archiving a coupon: archive

Archives a coupon when you want to keep a record of it, without cluttering your current stash of coupons.

To view archived coupons, the user can run the list a/ command to list all archived coupons. Alternatively, the find command explained below will search all archived coupons, thus displaying archives that match the supplied keywords below unarchived coupons. Finally, the expiring command will also include all archived coupons that are expiring in its results. Read the section on find and expiring respectively to find out more.

Format: archive INDEX

  • Archives the coupon at the specified INDEX.

Examples:

  • archive 1
    Archives the first coupon in the coupon list.

To keep your coupons more organized, Coupon Stash will automatically archive your coupons once their usage limit has been reached, or when they have expired.

Unarchiving a coupon: unarchive

Unarchive a coupon, thus bringing it back to your active coupons list.

To unarchive a coupon, you have to make sure that the archived coupon is visible in the Coupon Stash first. Read the section on the archive command to find out the ways that you can display archived coupons.

Format: unarchive INDEX

  • Unarchive the coupon at the specified INDEX.

Examples:

  • unarchive 1
    Unarchive the first coupon in the coupon list.

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.

Coupon Archiving

When physical coupons are expired or exhausted, they would usually be thrown away, or kept in the archive. Coupon Stash simulates this archive, storing these coupons in the app so that the user can still keep track of it, and the savings they generated.

Current Implementation

The archiving of coupons is facilitated by the Archived attribute of a coupon. The following methods in the CouponStash, Coupon, Usage, UsedCommand class and the Model interface facilitates this feature:

  • CouponStash#archiveExpiredCoupons() — Archives any coupon in the CouponStash that has expired, and returns a new updated CouponStash.

  • Coupon#increaseUsageByOne() - Increases the usage of a coupon by one.

  • Usage#isAtLimit - Returns true if the current usage is at its limit (abstracted by the Limit field).

  • UsedCommand#execute() - Executes the used command input by the user.

  • Model#PREDICATE_SHOW_ALL_ACTIVE_COUPONS - A Predicate function that filters out archived coupons from a given CouponStash.

ArchivingClassDiagram
Figure 1. Overview class diagram representation of the coupon archiving implementation.

Given below is two example usage scenarios and how the archiving mechanism behaves at each step of each scenario. An activity diagram is provided first to describe the general events that will lead to an automatic archiving of coupons by Coupon Stash.

ArchivingActivityDiagram
Figure 2. Activity diagram representation of the general flow of archiving of coupons in Coupon Stash

Archiving of Expired Coupons

Expired coupons are automatically archived by Coupon Stash upon start up of the application. The following steps describe how this behaviour is implemented.

Step 1. The user launches the application for the first time. The initiation of ModelManager will also trigger the initiation of CouponStash with any available saved data.

Step 2. The method CouponStash#archiveExpiredCoupons will be called from the newly initiated CouponStash, and have its UniqueCouponList mapped to a function that archive coupons that has expired before the date of opening the application, and returns a new updated CouponStash. This mapping function is facilitated by Coupon#hasExpired() and Coupon#archive().

Step 3. The ModelManager will proceed to filter out the archived coupons from the newly updated CouponStash, and return a filtered list of active coupons. This filtering is facilitated by the predicate Model#PREDICATE_SHOW_ALL_ACTIVE_COUPONS.

ArchiveExpiredSequenceDiagram
Figure 3. Sequence diagram representation of archiving expired coupons

Archiving of Exhausted Coupons

Coupons that have exhausted its usages will be automatically archived by the application. The following steps describe how this behaviour is implemented.

Step 1. The user uses a Coupon in the current observable CouponStash with the command used 1. UsedCommand is created with the parsed arguments, and executed. The particular Coupon will then have its Usage increased by one by calling Coupon#increaseUsageByOne().

Step 2. The Coupon will then be checked if its Usage has reached its Limit, using the Usage#isAtLimit() method. For the purpose of this explanation, we assume that the coupon being used has a usage Limit of 1 and a previous Usage value of 0, with savings in MonetaryAmount.

Step 3. The Coupon will have a new Archived value, which will be set to true if the Usage has indeed reached its Limit. This is facilitated by Coupon#archive().

Step 4. The CouponStash will be updated with this used Coupon with the ModelManager#setCoupon() method. Under the hood of this method, the current FilteredList will be updated to show active Coupons only, facilitated by the predicate Model#PREDICATE_SHOW_ALL_ACTIVE_COUPONS.

ArchiveExhaustedSequenceDiagram
Figure 4. Sequence diagram representation of archiving exhausted coupons

Design Considerations

Aspect: The implementation to store archived coupons
  • Alternative 1 (current choice): Coupon contains an Archived field

    • Pros: Easy to implement, lower maintainability.

    • Cons: Saved data may get get considerably huge after heavy usage of application.

  • Alternative 2: Archived Coupons are stored in another separate data file.

    • Pros: Separates the logic between the two different CouponStash, e.g. ability to limit the functions on archived Coupons

    • Cons: Sharply increases the maintainability and coupling of the application with two data files.

Alternative 1 was chosen, due to the cons of Alternative 2. While a separate file is akin to having two separate stashes of coupons, this would increase the overall complexity of the application. Logic and Model would have to deal with another set of data, and Commands may have to split up the logic for different data sets. Furthermore, while saved data will be larger for Alternative 1, it should only affect the performance of starting Coupon Stash up, since most of the interactions with the program is with active coupons.

PROJECT: Package


Overview

Package is a platform tailored to the needs of a specific food business, allowing for a seamless platform for both the business and its customers to use to order food packages. The platform manages food packages, menus, and the delivery area of customers, which can help save the business time and energy over using the conventional method of recording on paper and communicating over instant messaging.

Summary of contributions

  • Communicated with business client

  • Planned functionality of the platform

  • Designed platform UI on Figma

  • Build both frontend and backend from scratch

PROJECT: chestersim.dev


Overview

chestersim.dev is meant to be a personal website for myself, but was also used intially for me to build something with my newfound knowledge for React. An updated version is coming up soon!

PROJECT: MoneyMove$


Overview

MoneyMove$ is a project born out of the Razer Fintech Hackathon (video here at the 1:10:18 mark!). It is a savings/Sub-Accounts app that provides a curated, personalized content experience which ties directly into savings goals and habits. The app relies on Mambu’s APIs to create sub-accounts - buckets - for each item, good, or service the user desires. The team intends to offer a plethora of content for the user to save up to, including gaming, food deals, movies, events and even personal banking services. The project won the prize for the top 2 in the hackathon!

Summary of contribtions

  • Main frontend engineer - build the entire app in React Native

PROJECT: Clique


Overview

Clique was a project done by me and my partner for Project Orbital (CP2106, and won the Judge’s Choice Award. It is a messaging-cum-calendar mobile app, where we try to integrate events into messaging. Read more about it in depth in the repo!

Summary of contributions

  • Designed majority of the UI using Sketch

  • Developed and build equal share of both the frontend and the backend.