PROJECT: SocialCare

1. 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

2. 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 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: #76, #129

      • Rewrote the quick start section of the User Guide: #154

      • Revised content for the Logic component in the Developer Guide: #93

    • Community:

      • Reviewed PRs for team members (with non-trivial review comments): #58, #109, #114

    • Tools:

      • Integrated Travis to the Github repository

3. Contributions to the User Guide

Below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users._

3.1. 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.

switch execution
Figure 1. Execute switch -e
switch execution
Figure 2. manage 1 targets the event at index 1
manage
Figure 3. Labelled screenshot of what to expect after executing manage 1

Refer to the labelled sections in the figure above for the following changes:

  1. The panel displays the list of volunteers that you can assign to an event.

  2. Name of the event being managed and total number of volunteers assigned to it.

  3. The list of volunteers currently assigned to the event. It will be empty if there are no volunteers assigned.

3.2. 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.

switch
Figure 4. Panel display changing from list of volunteers to list of events

4. 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._

4.1. 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:

public class ManageCommand extends Command {
    //...
    @Override
    public CommandResult execute(Model model, CommandHistory history) throws CommandException {
        requireNonNull(model);

        List<Event> 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.

manage SD
Figure 5. Simplified sequence diagram for manage command
Design considerations
Aspect: Context switching (to volunteering records)
  • Alternative 1 (current choice): Utilize Context class used in the switch function. (See Switch command)

    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.

    Pros

    Implementation is easy.

    Cons

    Classes becomes tightly coupled. The UI component would have access to methods it does not need.

4.2. 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.

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:

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.

switch SD
Figure 6. Simplified sequence diagram of switch command
Design considerations
Aspect: How context is maintained
  • Alternative 1 (current choice): Create a new Context class.

    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.

    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.