project title: ready to work · i can use ddp to update my users location in real time, aswell as...

42
Module Code: Project Title: Name: Student No: Course Title: Year of Study: EE3615 Ready to work Gethin Jones 1422999 Digital Design 2017/18

Upload: others

Post on 26-May-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

Module Code:

Project Title:

Name:

Student No:

Course Title:

Year of Study:

EE3615

Ready to work

Gethin Jones

1422999

Digital Design

2017/18

Page 2: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all
Page 3: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

Contents:

Part 1 - Implementation

Part 2 - Evaluation

Title

1.1 Technical structure

Introduction

1.2 Functionality

1.3 Path to implementation

2

37

2

- System archetecture

- Main development

- Styling

- Prototyping

3

7

35

3

16

- File structure

4

5

Page

Page 4: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

1

1.1 IntroductionChoice of core technologies

Given the requirements of my final artefact, it was impor-tant to select the right combination of developent technol-ogies to ensure proper functionality of all of it’s features, as well as a smooth development experience. After some discussion with my project supervisor, I looked at a number of options for my implementation. Here I look at some of the core technologies chosen and how they integrate with my app designs.

Every Meteor project comes with a Mongo database. This is a free, open source noSQL database, which uses docu-ments similar to JSON. I have never used a noSQL datab-se so this provided a good opportunity to learn how to use its cross platform, document-oriented capabilities. Mon-goDB provides flexibility in data formats, and is designed for scalability which will be useful if my app has a lot of users.

Cordova is an open source mobile app development framework which allows multiple platforms to be target-ed with one code base. In Meteor, code that runs on the client can be inside a web browser, or a Cordova mobile app, where it can be embedded in a web view within a na-tive app. This means mobile apps can be created with just HTML, CSS and JavaScript, making it a great companion for a Meteor project. I can write my web app and then use Cordova to create a mobile app.

Foundation is an all in one solution for responsice front end design, providing a neat ffamily of frameworks and lots of pre-configured elements. It can be used to create aesthetic, usable interfaces with styles that can be easily updated. Having looked at a few front end frameworks I decided on Foundation because of its simplicity and good documentation, as I have never used a front end frame-work so this would help me integrate it in my project.

Meteor is a full stack framework that includes code that runs on the client, code that runs on the server and shared common code. It is based entirely on JavaScript, with the server side code running inside a Node.js container. This means I could use what knowledge I had of JavaScript, while learning a new technology. Having never created a web app of this complexity before this was a helpful starting point. It provides the ability to specify what JS, templates, CSS and other assets to run and when, using import and export and default file load order.

DDP solves the problem of pushing changes in your data-base to the client. It allows you to query your server-side database, send the results to the client then push any changes to the client whenever anything changes. This means users can see updates immediately without waiting for a network response.

I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all users when changed (e.g if a job is new job is added, it would display instantly).

Meteor allows you to define methods on the server. The client can then call these arbitrary JavaScript functions. Meteor ensures the methods only execite once using re-connection and a replay cache. This will allow for easy updates of data which will be stored in a database.

Meteor is a built ontop of Node.js, using it to deploy apps, but with its own packaging system in place of node’s mod-ule based system. This makes it easy to make web applica-tions. While I do not need to interact with this technology directly it is useful to understand the underlying technolo-gy my app will rely on.

Blaze is Metors default template renering engine. It uses Spacebars, a templating language similar to handlebars. Spacebars is built to render changing data reactively, mak-ing it an excellent choice for my project given the nature of my data, which will need to update regularly. Spacebars templates appear the same as regular HTML, but with “mustache” tags which are delimited by curly braces: {{ }}.

Becuase of the real time requirements of the app, Meteor seemed like a great solution. It has a number of features which make it a good choice for my implementation.

Universal JavaScript

DDP (Distributed Data Protocol)

Server side methods

Meteor

MongoDB

ZURB Foundation

Apache Cordova

Blaze

Node.js

Page 5: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

2

Some packages make the aforementioned tech-noligies integrate into my meteor project. I have also used a number of packages from atmos-phere.js which are designed specifically for mete-or apps. These can intereact in soecial ways with meteors template rendering engine blaze. These packages add fucntionality such as user roles, and include useful methods for things such as user messaging.

Supplementary technologies

Google maps API’s

Meteor packages

Jquery

Jquery UITypical Meteor System Architecture

Page 6: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

3

Ready to work System Architecture

Front End

Data layer

Database

The system architecture for my app can be most simply visualised by this layered architecture pattern diagram. It shows the stack of the app, which uses MongoDB as the database layer, Meteor as the data layer and blaze as the front end. This is however very simplistic so I also created the diagram to the right, which shows the full architecture of the system and how the different components interact with each other.

This is the structure of my app, with all the different files. Files stored in the lib directory are loaded first by Meteor, so any setup is done in here including the configuration of accounts and database setup.

This diagram shows the full Ready to work system architecture, highlighting the key technologies which drive each component. The flow can be traced from the bottom left up to the output on the browser at the top. It shows how the database on server side interacts with the miniMongo client side cache via DDP, and the javascript via HTTP, explicitly by Method calls.

Development stack

System Architecture Diagram

File Structure

Page 7: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

4

1.2 Functionality

Apply for jobs Post new job listing

View job offers

Send job offers

Displaying active jobs

Completing jobs

View completed jobs

View open listings

View applications

Message owner

Accept offer

Withdraw application

Decline offer

View applications/ job offers

View my job listings

Working users Hiring users

The functionality of a web application can be defined as what the application does for a user, or it’s answer/ solu-tion to a set of needs or tasks. Based on my existing re-quirements and proposed feature set, here is the underly-ing functionality.

I have highlighted how each feauture behaves based on the technical specification of exactly what was needed in the development stages. For simplicity and readability, I have chosen to express the functionality in a structured format. I split into hiring, working or shared functionality.

Shared functionalitySign up

Log in

Description Creates a user account and logs into the system

Inputs Username, email and password from sign up form

Outputs New user document to users collection

Action Checks to see if username or email is already taken. Updates the users collection and renders the homepage

Requirements Valid email address

Description Logs the user into the system

Inputs Username OR email and password from log in form

Outputs None

Action Authentication checks to see if the user exists and if the pass-word is correct. If so logs in if not returns error.

Requirements Existing Ready to work account username or email and pwd

Send message

View messages

Add profile

Description Send a message to a selected user

Inputs Message button, message body and submit from new message form

Outputs New message added to messages collection

Action Check to see if conversation exists. If not add participants and send message to conversation.

Requirements Existing account and another user to message.

Description View messages from a given conversation

Inputs Select conversation from a list of conversations

Outputs N/A

Action Check for id of specified conversation. Query messages col-lection and return all messages for conversation. Update read state to true.

Requirements Existing conversation with messages.

Description Add some additional info to the users account

Inputs Text inputs from create new profile form

Outputs New fields added to user collection, data output to users pro-file page.

Action Check if profile exists, send call to server side method to up-date profile.v

Requirements User account, no profile.

System Features

Working user group- Signup and login feature for existing users, linked to a database holding user information with tables for each user group- User profile - record of user details, reviews and ratings- Job history - keep track of past shifts and view details of completed interactions with employers- Calendar/ schedule- view upcoming booked shifts which have been confirmed by employer- Map or list view showing locations of current available job offers- Search function with filters to search available jobs by type, location, pay, start time, and employer rating- Apply for job feature- send an application in response to a job broadcast, with your availability and suitability- Respond to job offers- ability to choose whether to be available/ on call for live job offers and respond to incom-ing offers.- Job confirmation- sign a digital contract with employers - Reminders - get reminders for upcoming shifts - Review feature - leave feedback on your employer after shifts for other users to view

Hiring user group- Real time location service of working users in order to provide accurate location based results for employer searches, displayed in a list or on a map for hiring user group.-Job offer broadcasting- send out a “tweet” style 100 character maximum job offer which can be viewed by us-ers on a map.- Respond to job requests - browse a shortlist of users who have responded to your broadcasts and select users who you would like to offer work-

Page 8: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

5

Working with templatesWorking in meteor allows you to create templates which can be rendered on screen at any time without needing a full page refresh.

To begin structuring my application, I created a new tem-plate for my header, which would then be included in every page before the main content.

The templates are defined after the closing body tag and can then be called anywhere in the application by includ-ing the blaze tags as seen in this example, which will ren-der any HTML included in the header tags in the body section.

This gives a basic example of how templates can be used in Meteor, but they have many more uses which will be explored and implemented in later sections.

A key advantage of working with templates is that it seper-ates your code, allowing maximum reusability and making it easy to find and change relevant things. It allows each component to be worked on and updated seperately, so changes can be easily made.

They also keep things organised with your JS, as we will see later- with the use of events and helpers containing template specific javascript.

accounts-ui

insecure

Collections in Meteor

All data in meteor is stored in collections, including for ex-ample the login data created by the accounts-ui package. The main collection alongside this is the jobs collection which stores all of the information about each job post.

DDP relies on realtime queries using “publish” on the server and then using “subscribe” on the client to connect and recieve the data and listen for any updates. Templates are then updated automatically by binding HTML ele-ments to the client side cache, with Meteor handing the rest. This can be seen in the next stage where I set up my new jobs collection.

The package allows you to call {{loginbuttons}} anywhere in your template, and the package handles the rest. Of course later on the code will have to be written for custom designed login, but this allows a rapid setup for testing accounts based features such as the map and jobs func-tionality.

The insecure package comes with every new meteor pro-ject by defualt. It automatically creates publications for you data, so you can test easily. Because I wanted to learn from the start how to use publications and subscriptions in meteor I removed insecure.

To get up and running quickly with Meteor, it comes with a couple of packages installed which would not be suited to production, but are great for getting set up and running with user accounts in no time.

To use meteor it must first be installed along with any de-pendencies. This is done with Terminal (on osx).

With the setup completed I created a new Meteor project with Meteor create command prompt, which created the file strucrture for my new prototype.

Part 1.3 Implementation

Environment

Setup and installation

To develop my app I used a number of development tools which would aid in the process.

IDE- Sublime textMeteor toys- Mongo DB visualiser, debugging, checking set session variables

Creating a meteor project

Page 9: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

6

The data from the collection is published by the server in publications which are subscribed to by the client. The data is updated via the server side methods which are also saved in the lib directory and imported at the start of my client side code.

Geocoding

For the jobs location, I used googles Geocoding to return a full address object from the user entered location. I set up variables to store latitude, longitude and formatted address from the returned address object.

Server side method ‘addJob’ is called with the data in-putted by the user, as well as the calculated latitude and longitude as arguments.

The method accesses the Jobs collection via the global variable defined in ‘db.js’ and the captured data is stored in a document in the collection with named fields. Each new job is also given fields for the user creating it, aswell as an automatically generated unique _id identifier and date field

The action of the form is captured by the submit event in the events for the new job template. Each input elements value is assigned to a variable which is then sent to a serv-er side method which updates the jobs database with the new data.

Adding job data

To create the Jobs collection, I included a new file called db.js in the lib directory of my application, to ensure Me-teor will load it first. The file simply creates a new jobs collection which can be accessed via the global variable ‘Jobs’.

I created a simple form to add data to the collection, where each field has a name attribute which allows its value to be accessed by main.js (client side). The form is wrapped in a blaze template if statement which will only render the form if there is a current user signed in.

‘/lib/db.js’

‘main.html’

HTML output

‘main.html’

‘/client/main.js’

‘/client/main.js’ ‘/server/main.js’

‘/client/main.js’

‘/lib/methods.js’Creating a working prototype

Publish and subscribe

Page 10: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

7

Displaying data to the user

I used blaze templates to render my stored job data. I wrote a meteor helper that points to the Jobs collection, returning all documents.

Add functionality- private & remove

In order for users to be able to remove their listings, I created a button on each listing which is only shown to the user who created it. To check if the current user is the ower I used a helper attached to the job template which returns true if the job owner is the current user.

I also created a toggle button for the owner to update the listing to be either hidden or visible to other users. The text on the button changes depending on the toggle state which is updated with the click event.

The setPrivate method finds the job from the collection, authorizes the user then updates the collection using $set

The deleteJob method finds the job from the collection, authorizes the user then removes the associated job docu-ment from the collection with .remove()

To ensure an empty form is displayed to the user once they have submitted a job, at the end of the submit event the HTML form input element values are set to nothing.

When either button is clicked, an event fires calling a serv-er side method which will either update the job private field to private or remove the job altogether. The methods are sent the id of the particular job so each button corre-sponds to the associated job.

To use this returned data, I first created a template with blaze wrappers for all of the fields in my job documents called ‘job’, which acts as the structure for each returned job. Each job is contained in an <li> element..

Container template iterates returned jobs and adds each <li> within a <ul> element to create a list of jobs.

‘main.html’

‘main.html’

‘main.html’

‘main.html’

HTML output

HTML output

‘/client/main.js’

‘/client/main.js’

‘/client/main.js’

‘/client/main.js’

‘/lib/methods.js’

‘/lib/methods.js’

Page 11: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

8

Creating the map required packages dburles:google-maps

Meteor provided a new way of initializing a google maps map that I wasn’t familiar with before, so it took me a while to get up and running. I created a template which would contain the map and embedded the map right into the template linking to a mapOptions function which is defined in the helpers for the map template.

Map options set the required buttons, positions and other initial options for the map, to get it displaying the relevant default functionality in my specifications to then further build on top of.

Now that I had created and initialized the map, I needed to create markers for each job so that working users could log in and see all the available jobs nearby them. The locations would be taken from the stored latitude and longitude in the jobs collection. For this early prototype I used regular variables to get up and running, but this will later be updated to use reactive variables so that the pins are removed when changes are made to the collection eg if job is deleted.

I addded the places library along with my API ley, to later access the geocomplete functionality of the google maps API

‘/client/main.js’

‘/client/main.js’

‘main.html’

HTML output

Page 12: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

9

Adding job markers to map

In order to display all the job locations, I first created a var-iable to store all the jobs which didnt belong to the current user, weren’t set to private and had a status of open, which is given to all jobs on creation.

Set timeout function was used to set an interval between adding each job. This is becuase in large scale meteor will not be able to handle trying at add all the markers at once, so they are added one at a time after a small delay.

This job list is then iterated over and I set up some vari-ables to store job data about each job which will be dis-played in an infowindow. Because space is limited in the infowindow, for the long description I created a variable substring of 50 characters to display, and included a view full details link to later open a modal with full details.

In this codeblock I then created the function to add a marker, using the coordinates stored in the jobs collection and called the function for each item in the jobs list.

A click listener is attached to each marker in the addMark-er() function, which opens the infowindow when the mark-er is clicked. The variables for data are concatinated into a long string of HTML which forms the structure of the infowindow.

Toggle Between map and list view

Now the map shows all the locations, I created the func-tionality to toggle between the map or list views when the toggle button is clicked. To achieve this I used a session variable which toggles between true and false each time the button is clicked. I then created a helper to return the value of the session variable.

Now within my templates I could use the helper to render either the map or the list view when the button is clicked. using blazes spacebars I checked the helper to see if toggle is set, and if it is render the job list from earlier, otherwise render the map. Now when the button is clicked, the template is automatically updated to show the relevant HTML.

‘/client/main.js’

‘/client/main.js’

‘/client/main.js’

Helper- ‘/client/main.js’

Event- ‘/client/main.js’

‘main.html’

‘/client/main.js’

HTML output HTML output

Page 13: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

10

Interface for Hiring users

For the Hiring users, the map no longer needs to display all the available jobs, but should show all the online users who are in a ‘working’ role, and optionally markers for jobs owned by the current ‘hiring’ user. The form for creating new jobs is also shown here.

My Job Postings

Aswell as displaying the new-job form, rather than all jobs being displayed, only those which were posted by the signed in user should be shown. I updated the template to have an else statement containing the hiring code.

Adding user roles

With the map and list functionality in place showing jobs for working users, I needed to set up the page display for hiring users. To do this I added user roles to my users with a package called allaning:roles.

alanning:roles

The package automatically creates a set of default roles for users, generally used for admin etc. It also comes with a set of predefined methods to add users to roles and per-form other checks on users.

For my implementation, I used the package in a slightly different way, adding a role to each user of either ‘hiring’ or ‘working’, which would be attached to their user profile.

Role specific rendering

The role would determine which interface to display to the user, rendering elements to specific to that role. As I want-ed my users to be able to view both interfaces, I created a <select> input for users to switch between roles.

Rendering the correct content to users

Certain parts of the code which were specifically for work-ing users could then be wrapped in if clauses which would only render if the user was in a working role. These use the allaning isInRole method, which queries the role field of the users collection to determine is a user is working or hiring.

Secondly, some javascript should only run if the user is in a working role. For example all the map script which sets markers for available jobs. I could have used the user roles here, but as I still wanted to display the map to users who have not got an account, I used to asscociated session var-iable to check the sessions userType (which is set to work-ing if there is no logged in user).

When the <select> element is changed, 2 things happen. Firstly, the users role in the database is updated by calling a dedicated server side method. This method checks per-missions, checks the target user and finally adds the select-ed value to the roles field in the database users collection, with the allaning:roles SetUserRoles method. A second role of ‘update-roles’ is added, which is required for users to update roles.

Secondly, a session variable is set for the users userType.This would also track the users current role and display content differently based on the users role.

‘/lib/methods.js’

‘main.html’

‘/client/main.js’

This combination of if statements in my javascript and use of the {{isInRole}} blaze helper allowed me to restrict the content depending on the role. This was used for the new-job form, which should only be available to hiring users. Now when you render the page, only the working specific elements are loaded and the working map scripts run.

HTML output

Page 14: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

11

The function first finds all users, which could optionally at this stage be filtered for only online users, however for now all users are taken. Then checks to see if markers variable exists and if not creates it.

The function then checks to see if a marker exists for each user and if not, filters to those in working role. The addmarker function sets up some content variables to hold the User data and adds a marker when called if the user is online (checked with mizzao:user-status).

Updating markers

Now that a marker is created for a job, the next time the script runs in the autorun block, the marker is removed if the user is no longer online or now in a working role, by setting the map for that particular marker to ‘null’. If they are still online, the position of the marker is updated to the stored user location. This location can be updated each time the autorun block runs.

Setting up reactive variables

The reactive variables are only initialized if the geolocation was successful. In this case, they store the Latitude and Longitude from the geolocation on the window object.

Calling update method

At the end of the autorun block, the updateUser method is called with the values stored on the window object. Since the autorun function will rerun if one of its reactive varia-bles changes, the updateUser call will be made with differ-ent values each time.

Error handling

The method first checks if the user being edited is also signed in, then that all the keys are allowed to be updated. It specifies only the latitude and logitude can be updat-ed and send the update, or throws an error if the keys are invalid or if the user being updated isn’t signed in.

Updating hiring Interface

Adding markers for online users

To really make use of meteors power, this stage of devel-opment involved a lot of learning. I knew I wanted to make use of Meteors live functionality, being able to update my map live as users move and sign in or out. To achieve this I used reactive variables, which store markers tied to each particular user, creating an association from which the marker can be shown or hidden depending on the users status and current job role.

This involves some fairly complex functionality. I set up an autorun function within the map temaplates onCreated(-function(). This contains the code for showing all the live users on the map, and at the end of the autorun block, a method called to update the users location, which will then rerun each time one of the autorun functions reactive variables changes.

Finding users Geolocation

At the end of the autorun function, I then set up a variable to store users geolocation data. This can then be used to update the stored latitude and longitude for each user.

Page 15: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

12

Creating hiring list view

Having set up the map view, I then completed the list view for hiring users and set up all the templates to only render when the current role was set to hiring. The list view was made in a similar way to the working users, re-turning a list of all users whose status is online. The miz-zao:user-statuspackage supplies an easy method for this and each user is automatically given a status of online, offline or idle depending on their browser activity.

Adding Current Users Location

Aswell as displaying the location of all online users, I also wanted the map to display the current users current loca-tion using geolocation. I already used Geolocation earlier in my script to locate the users, so I just copied this code and added a marker for the current users location to the map with a custom icon.

mdg:geolocation

Page 16: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

13

Now that I had all the basic functionality of the map proto-typed, I just needed to add an interface between working and hiring users- to allow messages to be sent to each other. I already set up buttons in my HTML which will trig-ger the new message events, so I just needed to write the event handlers, and create a messaging template.

To implement messaging, I first added a package called socialize. I installed its base-model, which all other packag-es extend, and then the :messaging package, which I used to create the messaging functionality between users.

Each time a user goes to message another user, I needed to first check if a conversation already exists between the two users and display it, or otherwise create a new one. Each template that contained a message button was given an event handler for the clicking of the message button.

To check if a conversation already exists I set up a query on the conversations collection to check and see if there was a conversation where the participants field contains both the current users ID and the ID of the user they want to message. This was stored in a variable called existingCon-vo. I could then use “if(existingConvo)” to check if a convo already exists. Only if there was a conversation with both participants, any code in this if statement would execute.

In order to make sure I had access to all the messages re-lated data, I set up the publications on the server and sub-scriptions on the client. In production I would subscribe to a specific conversation only when required, to ensure that messages are kept secure from other users, However for the time being I simply published and then subscribed to all the data to get up and running.

Socialize:messaging

Setting up event handlers for message buttons

Publish and subscribe

Setting up messages container

Adding packages: Socialize

Messaging functionality

Installing the socialize:messaging package creates 3 new collections in my database- conversations, participants and messages. It also comes with some helpful predefined methods which make it very easy to perform actions like sending a message to a conversation, without having to write your own server side methods. Simply call “.send-Message(‘message conent’)” on the conversation and the package takes care of the rest.

Before adding any new messages I decided it would be a good idea to create a template for the messaging inter-face. I set up a new template called userMessages. This is where I would display the messages for any selected conversation. I then created another template containing the userMessages template and a form to add a new mes-sage. This message container could then be updated with messages every time a “message” button event is fired.

For each templates event handler, the second participant given to the findOne query would change depending on the context of the button. E.g. in the userList template it would be “this._id” (referring to the user), for the job template it would be the “ownerId”(for the owner of the job) or on the map it would be found from the value at-tribute of the message button clicked. This snippet shows how the existingConvo variable is set up differently for the event handler for buttons on the job template.

If there was already a conversation I then set its _id to a session variable, which I could use in a helper function to return the correct messages to the userMessages tem-plate. If not, a new conversation was created using the socialize “new Conversation().save()”. This creates a new conversation, which I then added the target user to. The id of this new conversation was then set to the “convoId” session variable instead. The final line shows the messag-es container, which would be set up to display the conver-sation messages based on the convoId session variable.

‘/server/main.js’

‘/client/main.js’

‘/client/main.html’

Now every time a message button was clicked the session variable was set to the ID of the conversation to display. I created a helper function on my userMessages template which first gets the ID from the session variable using get() and then returns all messages which are associated with that ID, sorted by date.

Displaying the correct conversation

Page 17: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

14

I then updated the messages template to iterate over these messages and for each one display the username, a timestamp and the message content. This meant that now the userMessages template would display all messages from the conversation matching the session variable, and updates every time the session variable changes.

The interface was now set up to display messages from a conversation, but currently no conversations had any messages associated with them. To add new messages I needed to attach a handler to the submit event of the new-message form, to store the value of the input as a message.

I firstly created the new submit event for the new message template. The function stores the content of the message in a variable by using event.target to target the form, then content.value to get the value of the input which had been named “content”.

The message container was given an initial CSS display property of none, so that it would be hidden. I set it in a fixed position on the screen, and then every time the mes-sage user button was clicked the container is shown by the fadeIn() on the last line of the event.

With the messaging in place, I conducted various tests before going on to start developing the full feature set.

The function then gets the id of the active conversation from the session variable, and finds the conversation with the matching id. I then used the very handy socialize send-Message() method to store the message in the messages collection, with the id of the conversation, so that they can be accessed later.

As meteor uses DDP, the data is instantly pushed to all instances of this conversation, meaning that the messages appear instantly. Each conversation in socialize has a read state determining if the conversation has bbeen read of not bby each participant. When a message was sent. the conversation remained in an unRead state for all users, even the person who sent the message, so I included a manual updateReadState() on the conversation to set the conversation read state to true for the sender.

I then clear the input for the user. Finally I added a line to my function to scroll the messages div that contained all the messages. Becuase the messages appear instantly, they were being added to the list of messages but you had to scroll down to see them. Adding this line ensured the messages scroll up to reveal the new one when sent.

Sending messages

Functional styling

Page 18: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

15

‘main.scss’

With the prototype code as a starting point I could now develop my full application. The prototype demonstrates the maps basic functionality for both hiring and working users and messages between them. It does not however include any styling or the rest of functionality.

Some features require additional technologies to create. Aswell as this, building the full application on a front end framework will mean styled elements can be included as an integral part of the process. At this stage I decided to integrate some additional tenonologies to my project and begin developing my full application.

Meteor uses URL’s differently to most websites. I added flowrouter to easily create views out of my templates for my different page URLs. Installed flowrouter and set up routes to each URL displaying the template associated to it.

A package I installed to create alerts for users.

I decided to throw in some styles to help the artefact take better shape. I used Zurb Foundation as a front end frame-work to help me build basic elements and add responsivity to build upon in my development.

To use foundation with my meteor project I installed some packages, fourseven:scss (a dependancy of foundation) and zurb:foundation-sites. Because foundation uses SASS, any existing CSS files were updated into my main.scss file and the foundation styles imported.

Having installed foundation, my app looked slightly differ-ent, with the HTML elements taking on Foundation’s de-fault styles. I could now begin using foundation as a build-ing tool for new elements in my application, providing easily editable styles and responsivity. Some Foundation elements require javascript, so need to set up and then initialized with $(document).foundation();

Adding ZURB Foundation Framework

Adding FlowRouter

SweetAlert

AccountsPassword

Mobile First Styling

While creating my main app, I will use mobile first styling meaning that components are styled for mobile in their defualt state and then media queries used to change the style for incrementally larger screens with min-width que-ries.. In some cases I may use max-width for styles only un-der a certain width. This approach means that all the fea-tures will operate well on mobile and nothing is restricted as all the content fits into the mobile design and then can be spaced out hideen content shown on larger screens

Main development

Modal windows

Foundation comes with its own modal windows which it calls “reveals”. These elements are hidden off screen until triggered by an event. These are useful to display content when a link is clicked, and are by default responsive, taking up full width on smaller viewports. I decided to use these to house some of my functionality, which could then be accessed through links within the templates.

Create a “Meteor.users” collection to store the user’s data.Provide the foundation for an accounts system that relies on an email and a password for registration and logging-in.Provide us with a number of useful functions to speed up development.This means we can focus on building the parts of the application that the users actually see while focusing as little as possible on the boring stuff that the developers of Meteor have already taken care of.

Page 19: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

16

As all pages in my app design share a common header, I decided to implement this first. I created a new template to house the header code, meaning that it could be in-cluded on any page, any any associated javascript would be stored in its template helpers and events.

The header contains a link which will open the login modal when clicked. This modal contains the {{atForm}} template which is created by the accounts-password package which I configured when adding the package. I used an “unless” statement to only show the login links if the user wasn’t signed in.

To replace the log in links when a user signs in, I created a logout button which appears next to a menu. I created the menu using a foundation accordian-menu element. I first created a new template for the accordion menu named “accord” then wrote the menu code.

The accordion menu displays the links when clicked. Currently the links do not do anything, with the exception of log out, which can share the funtional-ity of the main log out function which simply calls Meteor.logout()

Firstly I added an <img> attribute to my template with an id of “mainLogo”. I set the source of my image to 1 of 2 main logo files, 1 being thinner for smaller screens.

The menu is comprised of a <ul> element with the classes “vertical menu accordion-menu”. Within this is the logged in users username in an <li> wrapped in an <a> element. This is all that will be displayed to the user until they click the name. The <li> has a nested <ul> which then contains all the User navigation links. I included a log in link, which would be displayed on small screens but hidden on large screens where the full size logout is shown, next to the accordion menu.

I then set up the javascipt for the menu using its id in an onrendered function for the template that holds it:

Throughout the development of my application I will be using responsive units so that everything scales correct-ly including with changes in the browsers zoom for users with visual impairment.

For the header, the width was set to 100% and all contents were sized with either percentages em/rems or relative to the viewport eg with vh and vw. Meteor has a handy rem calculator which allows units to be specified as a pix-el value and Meteor will calculate the rem value. Do use this I just specify rem-calc(‘pixel value) for size rules in my styling.

In order to show the correct logo depending on the screen size, I then created a media query to serve the thinner image to screens smaller than 600px, and the full logo to larger screens. There is traditionally no way to change an <img> source attribute in CSS without using Javascript, however you can use

content:url(‘/images/logo.png’);

This seemed to work great for me, but then during testing realised that in Firefox it wasn’t working. For now I left this working in google chrome, but would need to implement a different javascript to change the image source, or make use of a foundation feature which does this automatically for you. Alternatively I could look at changing the <img> to a <div> and adding a background image which could be changed with media queries.

I used the logo’s ID to style it, with different styles in a mesdia query for the smaller logo. For the sizing I used responsive units to ensure that the image was flexible and would scale depending on viewport size. The width was specified in vw, meaning its 25% of the viewport width, meaning on larger devices the logo would get bigger and make more use of the space. I centered by setting to left 50% and then setting the left margin to a negative value of half the width.

Responsive logo

Responsive units

Login/ sign up links

User menuCreating a responsive header

Page 20: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

17

To give the user some feedback of which page they were currently on, I decided to add a small version of the Ready To Work pin next to the page that the user is on.

I wrote a template event which would remove the pin and add a new one next to the clicked item using .remove() and prependTo()

Off canvas navigation

I decided that to keep things clean and minimal, the main navigation on the app would be hidden in an off screen element for all screen sizes. To do this I created a new tem-plate to house the off canvas content. Within this template I created a <div> with the class of “off-canvas” to create a new foundation off-canvas element.

This is hidden by default and triggered using the menu button in the header section, which was given a data-tog-gle attribute of the id of the new off-canvas.

To create icons next to each navigation link I used font awe-some.

The icon was specified with the class “fa-” followed by the name of the icon from the Font Awe-some library. I selected icons for each element and set a hover rule in my sass file to change the background colour when a user hovers over the list item.

Showing user active page

To ensure that when the page loaded the correct pin would be loaded for the page the user is on, I also wrote some code in the Meteor startup codeblock to create the pin next to the icon corresponding to the current page.

The code creates a new pin and then gets the href of the current pages url. I then split this into parts to get the last part after the “/” using split() and then added the pin to the link of this value using prependTo and finding the link with the href equivalent to the value. This shows the pin when the page loads next to the correct link.

Within the off-canvas navigation, I wanted to give a visual cue for users if they had new messages, showing a badge containing the number of conversations with new messag-es.

To implement this I added a helper function to the tem-plate, which returns the number, or false if there are none. The function first finds all conversations the user is partici-pating in, then increments a count, if the user has not read the messages.

Menu Icons

FontAwesome

Showing Inbox unread count

Within the off-canvas <div> I created a close button and added a “data-close” attribute to then close the menu again. This was styled to be in the same place as the open button so that it is easy to toggle it open and closed.

The rest of the code is for the navigation items which are all contained in an unordered list. I listed all the pages of my app and gave each a corresponding “href” attribute, pointing to URL’s which I would use later with flowRouter when creating additional pages.

HTML output

‘/client/main.js’

‘/client/main.html’

Page 21: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

18

In the allJobs template, I created a control bar <div> to house the existing map controls (eg the select box and view toggle button), as well as the role specific links to modal windows. I copied the control code into this <div> then created another for the main section. The alljobs tem-plate then had the following structure:

The main page of my app is made up of the {{>header}} template and a main section which contains the map and list views for job data created in the prototype. I created a template called allJobs to hold the main section content and copied all of the prototype code into it.

I then created another template called home. This tem-plate would be the one loaded when a user visits the index of the site. I used dynamic template tags for the 2 sec-tions, top for header and then the main section.

Creating the controls bar

Making things responsive

Setting up page structure

Creating the homepage

Modal windows

Each of the links in the controls bar will trigger its own modal window for the particular action. These will all be built in seperate templates with their own helpers and events. The content for the ‘Post new job listing’ already exists in its basic form from the prototype, so this will be able to be copied into a new modal, and then new modals created for the other user actions. These templates will be built in such a way that they can be recyled into other parts of the app where the same functionality is required.

Aswell as the links I added a filter button which would toggle the filter controls. I created another new template called filters which for now I added a couple of compo-nents to later configure, including a select and a slider.

I then added this template to the end of my control bar template and styled it so that it would have the same width as the rest of the controls and sit just underneath with the display property to none. I styled the page in such a way that the mainSection <div> underneath the controls bar would obscure the filters section of the controls bar in its initial state. I achieved this by setting the height of the mainSection <div> to the viewport height minus the head-er and controls bar using calc() and having it fixed to the bottom.

To populate to home template with my content, I created a new file in the lib directory of my app called routes.js. In this file I defined routes with FlowRouter. In this route, when the user visits ‘/’, the home template is rendered with the header and allJobs templates.

‘/client/main.html’

‘/client/main.scss’

‘/lib/routes.js’

I then split the code for the control bar elements into sep-erate templates. The select and view controls would stay the same for all users but the control links would be role specific, so a template was created for each.

I then had a select template, jobContols template (holding toggle view button and filter button), and 2 new templates for hiringLinks and workingLinks. These were given the links for each user role to perform actions for the users once I implement the functionality for applying for jobs and sending job offers.

The above image shows the new templates with links. Beside is the final structure of the controlbar div, rendering different control links to the user depending on the se-lected role- see the browser output below.

I then added an event to the jobControls template (con-taining the filter button) so that when it was clicked, the fil-ters <div> would fade in and the maps height recalculated with the new height of the controlsBar (now including the filters). I also added a class on filtersBtnOn so that I could write the same in reverse to then hide the filters again.

Aswell as using responsive units in my measurements, I added media queries to display the homepage content ifferently on different sized screeens. This is discussed later in the report.

Filter button

Page 22: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

19

The functionality for sending job offers to users was im-plemented in a very similar way. I added job offer buttons which this time store the id of the user in the value attrib-ute of each button. These buttons were added to the list view and would also be added to the hiring users job list-ings in a list of applicants. The click event gets the _id of the user the offer is being sent to and again push this val-ue to an array in a new field in the Jobs document called “offers” via a server side method called sendOffer.

Apply for jobs Send job offers

Setting up jobs functionality

Updating database

Adding user buttons

Working users Hiring users

With the homepage templates in place, I could now im-plement some additional functionality in the page. This would mean I could update the links in my controls bar to complete the actions and show modal windows with the correct data to the user. The functionality can be broken down into the Hiring and Working users functionality and is as follows:

Applying for jobs (working users)

Sending job offers (hiring users)

In order for my working users to be able to apply to jobs, I needed to make some changes to my jobs collection and also provide some additional “APPLY” buttons to the map and list views of the mainSection code of my homepage.

Once this functionality is in place, I will be able to com-plete the rest of the action links in the job control bar.

Event handers System feedback

To store job application for each job I had a couple of options. Either create a new collection of applications with fields for the Job and applicant id’s OR use an embedded document to store applications in an array within the jobs collection. Each method has its advantages, but for now I chose to create a new field in the Jobs collection called “applicants” which would store the _id of each person who applies for the job in an array.

As the context of the apply button is different depend-ing on the view, the click event must be defined in the job template events for when it is clicked on the list view, which is simply a list of jobs each with an attached apply button.

I also needed an event for the map template so that when the button in the infowindows are clicked, the associated job can be found. In both cases I need to send the job ID to a method call which takes the id and update the appli-cants field of the corresponding job with the _id of the current user.

For the job template event, I used ‘this._id’ to find the job that the user was applying for. I then checked to see if the users ID was already in the applicants array to determine if they had already applied for the job before sending the call to the applyToJob method.

I then created buttons for each job so that the user could click apply wherever they are viewing a job. In the map view this meant updating the contentString variable I used to set content for the InfoWindows for each job to include the HTML for a button with the value of the jobs id.

In the list view I simply added the same html to the job template without the class, as in this instance I could ac-cess the job with this._id referring to the job.

‘/lib/methods.js’

‘/lib/methods.js’

‘/client/main.js’

‘/client/main.js’

In the map template event I simply copied the same code but changed the applyingFor variable to get the id of the job from the value I assigned to each button in the map.

SweetAlert: I used this package to replace standard alerts with a more elegant display to give the user feedback. When they apply for a job they have already applied for, they are greeted with an info window updating them of the situation and the call is not made to the server.

If the user is not in the array, the call is made and they are given a success message including the Title of the job they applied for which was stored in a variable in the event. In production an additional check will need to be made for any errors during the application, and return an error alert instead of the success. However for now this will suffice.

Page 23: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

20

1. View applications (working users)

Now that the jobs collection has fields with arrays holding applicants and job offers, it can be queried with helpers to return jobs which a user has applied for or been sent a job offer for working users, or return a list of applicants for a job for hiring users. On this basis, I could create all of the modal windows for the control bar on the homepage which are as follows:

in order to view applications that a user made, the Jobs collection is queried to return all jobs where the applicants array contains the users id. Before adding any content to the myApplications template, I created this template help-er to ran that query on the jobs collection returning all jobs where the user is an applicant.

Then in the template’s HTML I could iterate each applica-tion returned from the applications function and display the Job details. each instance is given some basic styling here to see the output when the template is rendered.

The events associated with these buttons could then be defined so the buttons would do their job.

Message user- The message user button was given a class of messageUser, the same as used with the message but-tons on the job template. This meant I could copy the code and simply ensure that during the checks to see if a new conversation exists (or initialisation of a new conversa-tion), the function is passed the ownerId field from the job as the participant to add to the conversation. Here is the click event from the myApplications events.

To break this down, the function first checks if a conver-sation exists with the participants including the job own-er and the current user. If it exists, the conversation id is stored in a session variable (which will then be used by the messaging template helper to return the messages for the selected conversation. If no existing conversation exists, the function creates one and adds the job owner as a participant and again setting the session variable. After either case, the messages element is faded in and now either shows the messages from the conversation, or is ready to send a message to the conversation initialized by the event.

Withdraw application- When the withdraw button is clicked, a server side method is called which takes the id of the job using this._id as the application data refers to the a job.

The method finds the job in the jobs collection from the given id and updates the applicants field, removing the us-ers id from the array using $pull. When clicked, the job will instantly disappear from the applications view, as the job no longer has the user as an applicant and so the template will no longer show the job.

‘/client/main.js’

Browswer output of each application

‘/client/main.js’

‘/client/main.js’

‘/client/main.js’

Querying Jobs collection

Displaying applications

Event handers

User actionsPost new job listing

Job offers

My applications

View my job listings

Working users Hiring users

With each returned job that the user has applied for, the template renders some buttons to either message the owner of the job, or withdraw the application.

‘/lib/methods.js’

The initial place I want to include the applications is in a modal window, to then be linked to from the job controls bar. I created a new template called myApplicationsMod-al, containing the myApplications template wrapped in a reveal. The reason for seperating the myApplications and myApplicationsModal templates is so that the returned set of jobs can be recycled on the “My Jobs” page of my ap-plication, which will show a summary of all the job related data for both hiring and working users.

Creating modal window

Creating Modals

Page 24: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

21

I then updated the “My applications” link in the work-ingLinks template to include the toggle-modal class and data-open attribute to open the applications modal when clicked. This now meant that users could get a view of their applications from the homepage.

Creating the modal windows proved to be initially a little difficult as this was my first time using both meteor and foundation. Initially I was having no luck getting the modal windows to show, and after some research and debugging I then realised it was becuase the modal templates had not been included anywhere on my page. To fix this, I sim-

The modal template also contains a title and an icon to identify the presented data for the user. It also contains the standard close button used in all of the apps modal windows. Foundation handles this when the data-close attribute is specifiied.

The “My applications” link in the template was then up-dated to display the returned value from the helper in brackets next to the link name, using the blaze helper han-dlebars for the {{appCount}} function.

Now when the page is rendered, the controlsBar working-links contains the updated applications link with counter, which when clicked toggles the modal window.

The View job offers modal operates in a very similar way to the applications modal. I again set up 2 new templates, one to house the job offers returned from the database, and the second to house this template along with a title and an icon in a modal window. The “view job offers” link was updated in the same way to include the toggle modal class and a data-open attribute linking to the ID of the new modal window.

To create the content for the View job offers modal, a different query was written in a helper function for the new template. This helper returns all jobs where the offers field array contains the users ID.

With the template being supplied a list of Jobs from the helper, I again used {{#each}} to iterate over the results and render the job details for each job aswell as some but-tons to then either accept or decline the offer. The buttons were given a value of the _id of the Job so that the job could be identified when hooking up the accept/ decline functionality.

I also added another helper to the workingLinks tempate to return the count of job offers in the controls bar.

I also then created a helper function for the workingLinks template (which contains the “My applications” link). The helper returns a count of the number of jobs the current user has applied for eg jobs where Meteor.userId() is con-tainted in the applicants array.

ply added the spacebars link to the modal template in the container section of my main HTML body section. I cre-ated a section here which would then house all addtional modal templates. Having included this, the modal window now showed when the user clicked on the working link.

Creating link to applications modal

Problems & difficulties

Displaying application count

Browswer output of myApplicationsModal

Browswer output

2. View job offers (working users)

‘/client/main.js’

‘/client/main.js’

‘/client/main.html’

‘/client/main.html’

‘/client/main.html’

Querying Jobs collection

Displaying Job offers

User actionsThese buttons will provide the functionality for the user to either accept or decline job offers presented to them in this view. When clicking on accept offer, I needed to up-date the job status so that it would no longer be available to other users, aswell as adding the accepted user to the job as a “hired user”. Declining the offer would remove the users name from the offers array in a similar way to the previous application modal using $pull.

Page 25: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

22

Updating database to accept job offersIn order to display only jobs to users which have not yet been completed or a user hired, I added a “status” field to the jobs collection, which would be set to “open” by de-fault when a job is created. This could then be changed to “closed” when a user is hired, and eventually “completed” once the job has been finished.

I also needed a place to store the hired user/ users. To do this I created an empty field called “hiredUser” which would store the ID of a user once they have accepted an offer to work. This is just a regular field which will hold one value, but in later developments this could be changed to hold an array, so that more than one user could be hired for each job.

Meteor Toys DB Visualisation

Event handers

Updating views when a user is hired

Now when each new job is created, users can apply and job offers can be sent by the owner, and the newly created fields are ready to be updated when a job offer is accept-ed. Above is a snippet from the Job collection, showing an example of a typical job at this stage.

Now with the database primed, I set up the event handlers for the “accept” and “decline buttons. Both buttons have associated jobs ID stored in their value attribute, making it easy for me to find and update the job in my database for either action.

Accept job offer- I created an events section for the job of-fers template. I added a click event handler for the accept button with a function to update the Job.

First the Job is found by using MongoDB’s findOne() to return the job an ID matching the ID in the buttons value. I then created an “if” statement to check if the hiredUser field had yet been populated, meaning that another user had been hired. While I could simply remove all the offers so that users would no longer see the offer once taken, I thought this would create confusion with jobs disappear-ing.

A better solution, I thought, would be to leave all the job offers, but then only show buttons if the job is still open. The above if statement would then act as a fallback in case the user somehow still sees the buttons for a job that is now closed, letting them know that they have just missed out.

If there is no hired user, a call is made to the accept job offer method, which adds the users ID to the hiredUser field of the associated job and updates its status to closed. I could then update my working users queries to only show jobs which still have a status of open to avoid applications coming in after a user has been hired.

As well as providing an error message if the job is taken by another user, I wanted the view to update in the job offers window depending on if the job was still open, had been taken by another user of if the current user has accepted the offer. To do this I created another helper for the job offers template which checks if the current user is also the hired user. This will return true if the user is hired and false in all other cases.

Now, I could update the template to first check if a user has already been hired by checking the length of the hire-dUser field. Only then if there was no hired user would the buttons to apply or decline show. This would be the case even if it was the current user who was hired, so I added an additional if statement to check the returned value of the helper, and provide status to the user depending if it was them or someone else who is the hired user. This also provides a link to the “My jobs” page.

‘/client/main.js’

‘/client/main.html’

Browser output for each case

‘/client/main.js’

Decline offer- This works in the same way as the applica-tions withdrawl, removing the users ID from the offers array so that they no longer see the offer.

‘/lib/methods.js’

Page 26: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

23

3. Post new job listing (hiring users)

In my prototype I already had created a submit new job form, which was shown to hiring users above the map. I now wanted to rehome this into the modal window aswell as updating the form to include some additional features.

I created a new template called newJobModal, which simply contained the newjob template wrapped in a <div> with the class of “reveal” and a “data-reveal” attribute. Foundation automatically created a reveal with the con-tents of this <div>.

This meant the form was no longer visible on the page, so I needed to create a way to display it. The form should only appear to users when they click on the link, so I set up the hiringLinks link.

Migrating form to modal window

In order to trigger the new-job modal when the link was clicked, a class of “toggle-modal” with a data-open attrib-ute linking to the newly created modal from the control bar. This now showed the original protoype new job form in a window when clicked.

Having migrated the new job form to my new modal win-dow, I decided to update the form by adding some new technologies to make it more usable and add some styl-ing. All the functionality from the prototype was working so jobs could be added from the modal, but the interface was very simple and did not provide any validation or sys-tem feedback for the user.

Creating link to new job form modalNow that my new job template was hidden, I needed to update the control bar link to open the modal when the link was clicked.

Updating post new job formAs well as the initial job info included in my prototype, the jobs collection also needed to include job requirements. This is optional for users, but instead of simply making the field optional I wanted to create an interface which only shows the input element when a button is clicked. I added 2 new buttons to the form and added event listeners which create a new input element within the form when clicked with a class of either “skills” or “experience”.

One useful feature I wanted to add to the new-job form was googles autocomplete, which is based on the places library I included in my map options. Currently, the form tries to geocode whatever input is entered into the single location field. This is prone to errors and currently has no check to see if the location is valid. By adding autocom-plete I could provide the user with a list of recommenda-tions when they start typing, which would provide a quick-er and more accurate way to enter the jobs location.

To implement this I gave the location input element an id of”autocomplete” and then initialized the autocomplete in an onRendered function for the new job template, so that the autocomplete works when the new job form renders.

Google autocomplete

Experience and skills fields I updated the submit event on the form to include fields for experience which pushes the values from each of the experience or skill inputs to an array.

The events for experience and skills are almost identical. The functions create a new input field each time the but-ton is clicked, along with a remove button. Both of these elements are added to a container, which is then added to the template just above the add new button using be-fore(). I then focus on the new input so it can used. In a seperate event, I added the handler for when the remove button is clicked, which takes the event target (clicked remove button) and removes its parent, meaning it along with the input field are removed.

I then updated the server side new job method to include the experience and skills field too with each new job.

‘/client/main.js’

‘/client/main.js’

‘/client/main.js’

‘/client/main.js’

Page 27: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

24

Jquery UI datepicker

Validation

System feedback

Error handling

Another field that was required on the new job form was the jobs start date. I wanted this to have a default value of ASAP, but then allow users to select a date in the future if requred to specify the starting date of their new job.

Rather than have the users enter the date and validate it for the correct format, I decided to use Jquery UI’s datepicker functionality to create a calendar view from which the date could be selected and then sent to the da-tabase with the rest of the job data on form submit.

To implement this, I first created 2 radio inputs on the form inside a <div> element which would house all the start date related elements, including those added by jquery.

I set the ASAP input to be the default value and gave both a name of startDate to locate the values in my job submit function. I then added an event handler for click events on the “Select” radio input, which creates a new input ele-ment to house the selected date, as well as focusing on this element which triggers its own event handler.

When focused, the new text input initializes a new instance of datepicker() by targeting the element and specifying any options, here the date format. The datepicker is then given a default value of todays date whenever it is focused on. Now when the date is changed on the datepicker, the value of the input changes to the corresponding date.

To update the submit event of the form, I then created a variable to store the value of the radio buttons, which would either be ASAP or Select. In the case it was ASAP, this can be sent as the value, but if a date was selected this should be the value not “select”. I wrote an in statement which updates the startDate variable to the value of the datepicker input if the radio is set to select.

Clicking on the “select” radio button first checks to see if the text input field already exists and if not creates a new input element on the form with an id of “myStartDate” which would become the datepicker element. After cre-ating the element the event handler then focuses on the new element which triggers another event handler.

When the select option is clicked, input is cre-ated and focused, the focus event triggers and the datepicker is shown on the template

Finally, I added a handler to the ASAP radio, to remove the datepicker again if ASAP is reselected.

I decided to implement a couple of visual cues for the user. Firstly, on a successful submission, an alert would dis-play to tell the user that their job has been posted. I used sweetalert for this with a success argument.

As well as thing I wanted to display a character count for the description, telling them how many characters they had remaining as they typed to ensure concise descrip-tions. To implement this I added a <span> element after the description input with a default content reading “You have 80 chars remaining”. This was the max amount of characters to allow.

I then created an event handler for the new job template for every time something was input into the description field. Using input instead of keydown meant only when a character was typed would the event fire. The event checks to see if the description is over 80 characters, in which case the event returns false before going any further. If not, the <span> content is updated to show the remaining charac-ters by subtracting the length from the max length.

The fields in my form have an input type, meaning only correct type of data can be input. However for more ro-bust validation I needed to include some further checks. aldeed:simple-schema is a package that provides exactly that, which I can add later to ensure all fields are properly validated against a schema which is created for the form.

Again, at this stage there is little error handling, with a failed job post failing silently in the background. I would later need to check for errors when the form is submitted and display relevant feedback to the user and take appro-priate action for each error.

Page 28: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

25

4. View my job listings (hiring users)

Displaying applicants

Getting applicant data

Towards the end of my protoype, I added a very rough draft version of this feature, with the hiring interface dis-playing a list view of jobs that the user has posted. I want-ed to rehome this data into a modal window, and add additional functionality so the user could take actions on the job data. This could now also be updated to display all of the applicants for the job and the job status, since these fields in the database has been created.

The hiring and working users share one template for jobs, which is then specified different jobs depending on its context and the user role. I created a template called my-JobPostings which displays the job template for every job wich the user is the owner.

Migrating template to modal window

Updating Job template

Adding job status Creating Nested Accordion Menu

Nesting another accordion menuI then created another template called myJobPosting-sModal, in which I added the myJobPostings template wrapped in an if statement to only render the template if the user is in a hiring role.

The job template already contains if statements to check if the user if the owner to display the remove button and the toggle private/ public button. I added an additional field for the new status field which would also only be displayed if the user was the owner of the job.

The job template already contains if statements to check if the user if the owner to display the remove button and the toggle private/ public button. I added an additional field for the new status field which would also only be displayed if the user was the owner of the job.

Each job has an array of users who have applied. In order to get the data about each of these applicants from the ids, I created a new helper function for the jobs template to return all the Users who are an applicant for the job.

The helper uses Mongo DB’s $in query operator to find users whose _id is $in the jobs applicants field. Here, ‘this’ represents the current job for the {{#each jobs}} helper, so the new helper will be used for each job in turn.

In order to add applicants to the template, I could have just used {{applicants}} to return the array of user ID’s for each job. However this is not very readable and may end up making the posts very large if there are a lot of appli-cants. For this reason I decided to use a nested accordi-on-menu to house the applicants data returned from my helper for each applicant.

Firstly, I made a new <ul> element and added the rele-vant classes and attributes to make an accordion-menu similar to the one in my header. I added a title of “View applicants” as the first <li>. Within this I then created the nested <ul> which returns a <li> for each applicant in the applicants array with their username.

The output of the myJobPostings modal also uses the Job template which is used to display all the jobs for working users. This meant that the output for the hiring users con-tains the same fields, including the apply and message buttons. In order to render a more suitable output, I need-ed to make some updates to the job template, so that if the user was in a hiring role, rather than the apply and message buttons the user would see all of the applicants who have applied as well as the job status, toggle private button and delete links.

This is the browser output of the nested accordion, which is a lot more readable than the _ids, but does still not give any real useful function-ality to intereact with the users.

In order to provide a little more information about each applicant to the user, and some controls to send them a job offer/ message them, I nested another <ul>. Within the <li> for each applicant, I created another <ul> ac-cordion-menu element with fields containing more infor-mation about the user as well as a button to send a job request to the user. I included some additional outputs of fields for the user which would be added later in the pro-file section to show their Name and Bio, or a message to say it hasn’t been added yet.

Page 29: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

26

View job on map

Displaying Applicant count

Displaying Applicant online statusBrowser output

The menu could now be drilled down, from the initial state showing “View applicants”, to the list of applicants, to data about each applicant.

Now whenever a user logged in, their status would update to show them as online in-stantly without a page refresh.

I created a helper for the template to return the number of applicants for each job. This meant I could show the user the number of applications next to the “View applicants” link using View Applicants {{applicantsCount}}

For each job I then added a button to view the job on the map. The hiring view usually shows just online users, how-ever I wanted this button to allow users to add a marker for their selected job to see which users are nearby to the job location. To implement this I decided to use a session variable to store the selected job ID and then update the map template code to handle this functionality.

I now wrote the event handlers for any interaction done on the view job listings template, including send job offer and view on map. View on map- Most of the functionality for this button is handled by the map template, however to show the cor-rect marker when selected I needed to set some session variables .

To break this down, the event finds the job from the jobs ID and gets the users id from the buttons value which is set when the button is made in javascript. It then checks the offers array to see if the user has already been sent an offer, and if not, calls the sendJobOffer method to send a job offer through to the selected applicant.

I now wrote the event handlers for any interaction done on the view job listings template, including send job offer and view on map. View on map- Most of the functionality for this button is handled by the map template, however to show the cor-rect marker when selected I needed to set some session variables .

This event handler clears any existing session variables for viewOnMap then sets the job id to the session variable to be used in the map code. I also ensured the toggle ses-sion variable was set to false, to show the map view if the user was currently on the list view.

Send job offer- I created another event to handle what happens when the user clicks the send job offer button.

Given that I had access to the user data for each appli-cant, I thought it would be a useful feature to display whether a user was online or not when the hiring user was browsing them. I already had the user status availa-ble to me as part of the user collection, provided by the mizzao:user-status package which I installed to display online users on the map. For each user, after the “User-name:” label, I created if statements to check if the user was online using {{applicant.status.online}} to add a small icon and the word online in brackets next to their name.

By getting the helper to return false if there was a count of 0, I could wrap the code that displays the applicants in an if statement, so that it would only display if there had been an application. Otherwise instread of the accordion, a <span> would render to let the user know there were no applications.

Event handlers

Initializing the accoridon menus

Page 30: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

27

Querying Jobs collection for owned jobs

Creating addJobMarker() function

Adding custom markers

Calling the function

Adding marker to map on new job creation

With the modal windows in place, I needed to update the map template to allow for the functionality of showing hir-ing users jobs on the map, based on the session variable set by the “view on map” button.

The way this works is by actually creating markers for each of the jobs in the myJobListings for the hiring users. The session variable then controls which job to display to the user, setting the map propertly for all other markers to “null”. When a view on map button is clicked, the session variable updates to that jobs ID. This which triggers the current marker to be set to null, and the marker corre-sponding to the new selected job set to the map.

Updating map template (View on map)Now that this code was set up, the session variable could be changed from anywhere, and the corresponding job would be shown on the map. To make use of this I also de-cided to update this session variable when a new job was made , so that its position would be shown instantly on the map, with all online users around it. To do this, I edited the server side method so that once the job data is sent to the database, the session variable is set to the new jobs ID.

To do this I used docsInserted, which return the ID of the newly insterted job and sets it to the view on map variable.

In my map code, within the self autorun block just before adding live users to the map, I made a new query to the Jobs collection to return all the jobs that the current user was the owner of. I then started a forEach so that I could create a marker for each of these jobs.

After defining the function, still within the forEach loop, I checked to see if each of the markers matched the session variable for the job to display. If it did I ran the function to add the marker.

At this stage I thought it would be a good idea to also up-date the pins on the map. I struggled with this at first, but soon found it was very easy using custom png’s- I had just been getting the URL wrong as meteor treats the Public directory as the root directory when rendering, so i did not need to include this in the URL. I changed the marker to the ready to work pin. Below is the browser output of a pin which has been added to the map by clickibng the view on map button, with the infowindow content. Clicking on the job then triggers a new modal called myJobPost (as op-posed to myJobPostings) which I created showing just that particular job in a modal window.

I then handled the “else” case for if the marker did already exist. Markers could exist without being visible on the map. I again checked if the marker job ID matched the ses-sion variable and if it did, recentered the map, or if it didnt, set the map to null. This hides all other markers except for the marker matching the session variable.

Now whenever the “View on map” button is pressed, ex-isting markers are set to null and the new marker is either created if it doesnt already exist or it is shown on the map by changing its previously “null” map propertly to the map.instance which displays it on the map. This also re centers it, in case the user just wants to re do the action.

I created a function to add markers to the map with a drop animation for each new job. This function would however only be called if the job’s ID matched the session variable to show the job on the map. I configured the infolabel to show job info and then the last line sets the center of the map to the markers position when the marker is added.

Checking if marker already exists

Inside the foreach loop, I next initialized the markers if not done so already and then checked to see if the current job had a marker .

If a marker did not already exist, I needed to create a func-tion to add the markers to the map, or if it did to recenter on that marker.

Page 31: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

28

With the user links in place and the rest of the control bar functioning, I added the custom controls to the map inter-face. These were controls which were available to all users to enhance the map.

I created a new function for the new controls within the maps onCreated function, also inside the GoogleMaps.ready function to ensure correct loading.

Adding custom controls to map

Geolocation Button

Adding the buttons to map

Custom search control buttons

Search bar

Search button

The geolocation button is there to recenter the map on the users current location. For this I could also use geo-location but also had the location of users with accounts stored and updated in my database as a fallback.

The location is calculated with geolocation where it is available, otherwise using the current users location from users colleciton where available otherwise a prompt is giv-en to the user to turn on their location settings.

To add the buttons to the map, I used push() to add the new buttons to the desired position on the map.

Only the search and geolocation are visible in the initial state, and then using a combination of push() and pop() in event handlers, the buttons were shown (e.g only show the clear button if the user has inputted text in the search).

I used the default bounds but could later change to restrict the search area if required. The new input element is giv-en some attributes and the position set. the search box is then initialized with the default bounds. I then added an event listener for the searchbox which pans to the selected location when the user selects a place from the list.

I then created some more custom buttons to interact with the search providing additional functionality. These would hide and show depending on the search state. The 3 but-tons are for submitting search, clearing search, and geolo-cation.

Before adding the buttons to the map, I created event handlers to control their functionality.

The search button has 2 roles. It acts as a secondary way to submit the search, as some users may be more used to this. It also allows me a way to provide feedback on the search input. Firstly I set up an if statement to check if the user had inputted anything. If not I provided a custom alert, fading in a div with the message.

The function then goes on to handle the search if there is an input. Firstly the status of the geocoder is checked. Then, in brief, the lat and lng are calculated from the input using googles geocoding, and these are used to set the pan values for the map. It also clears the search and re-focuses on the input for another search. If the geocoding was not successful, the user is given another alert. The clear button was very easy, simply copying the lines of code that clear and focus on the input.

The first custom control I added was the search bar. I used googles maps places searchbox for this, so that it would also recommend places when the user typed which could be selected to pan the map to that location. I created a new input element and then it up as a SearchBox.

Initial state

Focus state

Type state

Page 32: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

29

Creating Inbox Page

Page setup

Page structure

Querying the database

Dislaying the messages

Sending messages

Usability and Styling

Displaying conversations

Firstly I created a new template for the inbox, which would replace the main content section of the page when the user navigates to ‘/inbox’. Next I set up the route, to update the dynamic home template with this content when the user navigates to that URL.

Now when the user navigates to ‘/inbox’ the header sec-tion stays the same but the main content is updated with the new inbox template content, currently empty.

The inbox page is made of 2 main sections wrapped in a container. The first is a list of coversations the user is participating in, and the second a space to show the messaged once the user has selected a conversation, and write new messages. I created a main container <div> with id of ‘inbox’, and then 2 <div> elements inside called “messagesCont” and “convoCont”.

In order to show the conversations and messages for a user, I needed to add some template helpers to query the database and return the relevant fields. I first added a helper which would return all conversations the user is a participant in and sort them by the most recent first.

In order to show the retuned converations from the helper function, in my inbox template I used the blaze spacebars {{#each}} to return the id of each conversation.

While this did create an ordered list of the conversations, the conversations collection alone did not have any data about the participants to display so I could display the username. I had real difficulty figuring out how to get the corresponding participants and after writing a very con-voluted solution, eventually found I could use conver-sation.participants (supplied by the socialize messaging package) I could then iterate through these using #each, to output the username of each conversation participant (does not include the current user).

Each conversation is wrapped in an <a> tag with an Id and href of the conversation _id, so that when clicked this value can be fetched. I also added an if statement here to show the online button and text next to online users.

Now when any of the conversations is clicked the messag-es are shown in the messagesCont <div>.

This functionality works in the same was as for the proto-type messaging. The new message form submit handler finds the conversation from the convoId session variable and sends the forms input content to the conversation with conversation.sendMessage()

The main styling of the page was fairly simple and min-imal. The page is styled for mobile first, with the 2 main sections taking up 100% width and half of the viewport height each. Then on wider screens, I set the float prop-erty of the messages div so it would appear next to the conversations list.

To make the inbox functionality a little smoother I added some additional styles and if statements to display dif-ferent content depending on the page state. I added an if statement to the messages container to display a mes-sage asking the user to select a conversation if no convoId session variable was set.

I then created a helper to return if a conversation was selected, and a class was added if it returned true, adding border and shadow if the convo was the selected one.

I then added some extra data for each conversation in-cluding the last message, which I displayed in bold if un-read by checking if unread and adding a <strong> tags to the unread ones. The page was also set to scroll up when a new message sent to ensure it was visible. Now when a message is sent it appears instantly for each participant.

To display the messages I simply needed to display the same userMessages template that I set up when originally creating the messages modal in my prototype. This tem-plate has a helper that takes the value of session variable “convoId” and returns all the messages from the corre-sponding conversation. So, to ensure the correct messag-es would display when a conversation is clicked from the inbox, I needed to set the convoId session variable to that conversations ID.

I created a new click event handler for any of the conver-sation links in the inbox. This function takes the id of the link, which was earlier set to the conversation ID, and sets this to the convoId session variable. It also then updates the conversation read state to true, as the user will now have seen the conversation.

‘/lib/routes.js’

Page 33: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

30

Creating My Jobs Page

Page setup

Completing jobs

Displaying completed jobs

Displaying active jobs

I now set up the my Jobs page so that users could track their active jobs aswell as display a summary of all other user specific job related data. Like the homepage, the template will be shared hiring and working users, but ren-dering different sub templates and allowing for different actions depending on the role.

I first set up a new template called myJobs. As this page would also show different content based on whether the user was hiring or working, I included a link to the select template, which would allow users to change their role. I also updated the select so that its defult value would be set to the exising role of the user, so that users would not be confused by having to change the select unless they were both a working and hiring user.

Once a user has been hired, the job status for that job is changed to “closed” meaning it is no longer available to view on the map or list. These jobs can now be displayed to just the owner and the hired user on the my jobs page. The name is a little confusing, as closed refers to being closed for new applications, but the job is now essentially active for the hiring user and ired user and will remain this way until “completed” by the hiring user.

To show the active jobs, I created a new template called active jobs and then created 2 new helpers for it, one to return the jobs for hiring users and one for working users.

In the above snippet you can also see that for hiring users, a new button is created for each returned job. This button is used to complete jobs, a function only available to the hiring user, which will then allow both parties to rate each other. The button is given a value of the corresponding job _id and a class of markAsCompleted. I then set up an event handler for the clicking of these buttons.

The function gets the value of the button, which is the job id and then finds the job from the collection. The ids of both the hiring and working users are then stored and sent to a server side method along with the id of the job.

I created the method which first updates the job docu-ment in the collection (found using the supplied id) to have a jobStatus of completed. This means it would no longer appear in the active jobs section. I then also cre-ated a new field in the users collection which would store how many jobs they have completed (either working or hiring) to be used on their profile. To do this, i used mon-goDB’s $inc, to increment the value of the field by one for both the hiring and working users (also found by supplied ids).

When a hiring user completes a job, the jobStatus changes so neither user can see the job. I created a new template called createdJobs, which similar to active jobs would have 2 helpers for hiring and working users, but this time return-ing jobs with a status of “complete” rather than closed.

Then on the template I again used #each to iterate over each returned job and display the job title and hireduser/ owner.

Now that there was a place to display completed jobs, I could add in the rating functionality, so that both the hiring and working users could rate their experience with each other, and the ratings stored for each user to be displayed to other users on their profiles.

Both helpers only return jobs with the jobStatus set to closed. Then the working helper also filters to only include jobs where the hiredUser field matches their id, and for working users jobs where the ownerId matches their id.

Then in the activeJobs template, I created an if/else state-ment to render different data about the jobs depending on the role. If the user was working I displayed the title and owner for each job returned by the helper. Otherwise, the user was hiring and the template displays the title and hired user.

Page 34: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

31

Creating user ratings

Styling stars

Submitting rating

In order to rate users, I created an interface allowing users to rate wth a star rating, which would have an associated number value which could be used as a rating out of 5.

Within the completed jobs template, I added the follwing code within the each loop, so that it would be added to each completed job listing after the job title.

This displays a set of 5 stars using the fontAwesome library, each with a number and name value attached to it from 1 to 5, poor to excellent. I then added a submit button to trigger an event handler which would set the rating for the target user. The button was given a value of the either the job owners id or the hired users id depending to allow the right user to be updated. The above example is for the working users, so the job owner id is given as the value.

The stars come with a default colour but no way to select them or give any feedback to the user. To provide this I could use hover states, and clicked states to change the CSS of the stars making a much more usable experience.

I wanted to give the stars a highlight on hover. Using a regular hover event on the stars would only target the star itself, but I wanted to highlight the star aswell as all those before it eg. if you hover over star 4, then stars 1, 2, 3 and 4 will be highlighted. To achieve this I used javascript.

I created some event handlers for the stars to handle mouseenter and mouseleave events, which would trigger when the user hovered over or then off of the stars.

The mouseenter event gets the value of the star the user is hovering over, using event.target and then getting the data from the value attribute. I then used a complex se-lector to target all the children of the parent element, eg all the stars. Then for each of these I checked if their value was less than the value of the target star and if it was add-ed a class of hover, which changes the color of the star. The mouseout event simply removes this class again.

I now created a new event handler for the submit button of the stars. First the handler gets the rating by getting the value attached to the last star which has got the “se-lected” class after being clicked by the user. If there is no value, it means that the user hasn’t clicked on any of the stars yet, so a prompt is shown to supply a rating.

If there is a selected value the function continues to get the job ID from the data-job attribute on the submit but-ton so that the job can be updated saying the user has rated it, so they can be prevented from rating again. I then implemented a very basic rating calculation that just takes the rating value and makes an average of it and the users current rating. Of course, this is not a good way to store ratings as the average doesn’t take into account all the indivisual user ratings, just the total. In production, the rat-ings would be saved and the users rating calculated from an average of all the stored ratings. For now, I used this value.

I then checked to see if the user was the owner or the hired user and called some server side methods to set the rating value to the target user and then to update the job with a new field called either ownerRated or workerRated set to true. I then wrapped this code in an if statement to first check if the user had already rated, and if they had, give an error message.

I then created a click event which would add a different class of selected, to change the colour again, giving the user feedback on their selection. This does not submit the rating, but changes the colour. I initially really strug-gled with this as the click event was not registering for the containg <li> when the star inside was clicked. To fix this I added “pointerevents:none;” to the star so that only the <li> was clickable.

‘/client/ratings.scss’

‘/client/ratings.scss’

‘/client/main.js’

‘/lib/methods.js’

Page 35: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

32

Adding additional data to jobs page Final structure

System Feedback

The jobs page now contains a list of all active jobs for both user roles, a complete button for hiring users, a list of com-pleted jobs for both user roles with the ability to rate the user. As well as this functionality I wanted to have some additional data showing all the rest of the job data avail-able for that user including the still open jobs for hiring users and the applications and job offers for working users.

For the working users this was easy as I could just recycle the templates I already had. For the hiring users, I creat-ed a new template for the open job listings with a helper returning only job listings the user is the owner of that are open.

As this data was supplementary to the active and complet-ed data, I decided to house them in an accordion so that they would have to be clicked to open. I created a new <ul> with class of accordion and then within the content section put a link to the relevant templates which already existed. This was different for the working and hiring users, so 2 accordions were created with the relevant content.

At various points in the whole process, it is important to give the user some kind of visual cue as to the status of certain things. I added some if statements and checks to update the templates depending on the system state. Some examples of this are, hiding the rating buttons when a user rates, and giving a message to say they have rated. Also i created count helpers, to return a number for each section of the number of listings, which is especially useful if there are 0, as it indicates this rather than it being blank.

Page 36: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

33

Creating Profile Page

Page structure

Event handlers

Problems

Creating modal links for header

Styling

Page setup

I created another new template called profile and set up the routing so that the dynamic template would render this as the main section of the “/profile” page. When a user first signs up, they will not have a profile, so I also cre-ated another template to hold a new profile form.

This is a basic form which could be shown to new users, and also reused to allow users to edit their profile once set up.

The page is made up of one template, which either ren-ders the users profile, or the new profile template if they have not added a profile yet. To check if the user had a profile I simply checked for firstName, which is a required field on the profile form. If they had a first name set up they had a profile so I could show the rest of the profile.

If the currentUser does not have a firstName then the tem-plate instead renders the form to add a new profile. This form contains 2 text inputs for the first and last name and then a bio textarea allowing multiple lines of text. I also included an input with “file” type, to allow for file uploads.

I discovered a strange problem with the template which was moving the menu button from the header down the page when I added the profile template to the main dy-namic template. This was a big mystery and I could not find any real solution. I found that this only happened if the template only had one parent element in it eg the main <div>. As a quick fix to this I added a random ele-ment to the page and set the visibility to hidden with a small size as not to disrupt the layout (with “display:none;” the problem persisted.

I created the event handler for the form submit which gets the values from the fields in the form and then makes a call to a server side method which would send the values to the collection.

The profile page is very simple as there is not many fields to it. Later I would like to add with images for example but for now I simply arraged the contents gave the whole pro-file a margin to clear the header, aswell as a box shadow.

Now that I had a profile template, I updated the links in the header section to show the relevant profile modal when clicked so that the profile could be viewed or edited from any page in a small modal.

Now when the form is submitted, the template automat-ically updates to show the profile, as the user now has a firstName.

The user can then click the edit button, which shows the same form again, with the same actions, simply using $set to override the old data.

Some of the profile is made up from the users stats, which include the users ratings, and their number of completed jobs. This is shown at the top of the page and is not edita-ble by the user.

Below the stats the template displays the users Full name and then their bio. I used “currentUser”to allow me to get the data from the collection. Finally there is an “edit” but-ton, which is given attributes to toggle a modal which will contain the edit form for users to edit their profile.

‘/client/main.js’

‘/client/main.scss’

‘/lib/methods.js’

Browser output

Page 37: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

34

Creating custom login

Require login

Setting up session variables

To create a custom login page I removed the accounts-UI package and installed accounts-password. I then installed useraccounts:foundation which provides foundation styling support on top of the Meteor back end provided by ac-counts-password.

As well as creating the new login, I wanted to make all pages except the home screen locked unless a user was signed in. To do this I used a spacebars helper {{> en-sureSignedIn}}. This does not work on my dynamic tem-plates, so instead I created a new template for each of the “main:” parts to my dynamic template and within them linked to the original template. I then updated the routing so that these templates would load instead. Now when a logged out user tried to view those pages they were locked out until logging in.

I also updated my startup function as whe a user refreshed, I lost the session variables and so wrote a function to set the session variable to the current role of the user, or to a default of working if there was no user. The problem I had here was that when Meteor.startup runs, the Meteor.user() object has not been fully loaded yet so I was unable to get the values of the role. In order to wait until the data was loaded before checking for the Meteor.user object, I attached the function to the callback of the subscribe. This meant that only when the data was loaded was the check made.

Firstly I created a new file in my project called accounts-Config.js. This file contains default configuration which I copied and then added the above snippet to include a username field to the {{atForm}} template which the pack-age provides which will be replacing the {{loginButtons}} template I had been using to protoype with.

I then created a template called login box which I styled into a foundation reveal element. This would be triggered whenever the user clicks the login link.

‘/client/main.html’

‘/lib/routes.js’

Page 38: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

35

Responsive styling

In this section I will give a brief summary of the styling and responsivity for various key templates in the app. During implementation some crucial styling has been mentioned, but this provides a final overview of the app templates ex-mplaing how they were styled.

Having added all my functionality, I revisited all of the pages in my app to fine tune the layouts for each page, adding additional style rules to ensure they display correctly on all viewports. Each page is initially styled mobile first, with CSS media queries updating the layout at sensible breakpoints that are common for different devices.

Page 39: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

36

Homepage styling

iPhone 6/7 Plus+

Plenty of white space and bold buttons mean leading the users attention is easy and I can experiment with placement of the pages elements if I feel like changes need to be made. The main goal is to promote the content and provide a natu-ral progression through the system.

Page 40: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

37

My usability testing was fairly straightforward, with a simple goal of giving me insight on a number of key questions about the interface. I was slightly worried about how difficult users would find it to figure out the interface, especially given that it changes depending on their role. The main questions I seeked to answer were as follows:

How intuitive is the interface? Measure how easily the user couldnav-igate between each task, finding the associated controls.

How easy is the system language to understand? Measure how easi-ly the user understood system messages and labels.

How quickly can users respond to each task? Measure how long us-ers took to complete each task and any stumbling blocks they had.

Is there a clear pathway to complete each task? Measure how the users went about completing the task and if they found functionality right away or had to search or navigate to other pages first.

Is the visual design of the artefact suitable to the apps require-ments? Measure how the user responds to the styling

Is there anything the user can’t achieve that they would like to? Measure if the app fulfills the full requirements any highlight any additional functionality that would enhance the user experience.

I devised a set of tasks to give to each user in my study. I wanted to test the app from both a hiring and working perspective so I set up 2 different sets of tasks, asking half of my users to act as a working user and the other half as hiring users.

Working users- Create an account with their details- Add a profile to their account- Find their location on the map and apply for the closest job- Search for a location and apply for the closest job- Withdraw their application from the first job - Send a message to the owner of a job who has sent them an offer- Accept a job offer- View their active listings- Apply to a job from the list view

Hiring Users- Create an account with their details- Post a job - View a posted job on the map- Check how many applicants a job has- Send a message to a nearby user- Respond to a job application with a message

- Send a job offer to the applicant with the highest rating- View active jobs and complete their created job- Leave a rating for the completed job

Without ‘building’ my app, there was no easy way for me to allow us-ers to do a real walkthrough of my app, as I had no way to allow oth-er users to sign in and interact with them. In order to simulate this, I designed the tasks in such a way that after each one was completed, I could take over control of the screen and set up some initial states to complete the next tests. For example, after asking a hiring user to post a job, I updated the database collection to replicate the effect of a series of users having applied for the job.

Unfortunately this took away from the live aspect of the app, but still allowed me to test the usability by recording how well the users were able to complete each task and allowing them to interact with the system as though each initial state left off from the last task.

I also made some changes to the apps database so that the users would have some test data to interact with. I created a number of fake jobs at various locations and also set the online state to true for a number of users and set their locations at random locations on the map. Their locations would not update as they would with a live user, but this still allowed me to conduct tests like getting the hiring users to message a nearby online user.

2.1 User evaluationThere are a number of methods to evaluate my artefact from a user perspective. We can measure the efficiency of an interface at a high level e.g. using the GOMS model (Card, Moran & Newell, 1983), however one key limitation is it’s dependency on user skill level. Existing design principles (J. NIielsen, 1995; B. Tognazzini, 1978) can also provide guides for how we can measure usability for a wider audience.

Aswell as using this, usability testing is a good way to get insight into any pitfalls of my artefacts UI design and assess the perfor-mance and usefulness of the artefact from the point of view of the users.

I evaluated the design and implementation methods aswell as the key aspects of the interface which performed particularly well or badly during testing. I also looked at any innovative aspects of the site and whether they have provided instinctive usability, in line with established HCI design and evaluation techniques.

In order to give me something to evaluate against, I set up a range of system ideals which could be used to compare my results against.

Overview: - Functional needs and requirements. - Extracting needs from my system requirements to generate system ideals to test site interactions against.- Summary on how well the site meets needs through interactions.

Here are my set of heuristics for the site based on my functional and technical specifications aswell as the needs of my end users.

1. Intuitive across all platforms- Easy to navigate design.2. Predictable- actions can be planned to reach desired states.3. Clear visibility of system status- provides feedback on each step of process.4. Consistent system image5. Funtional/ visual consistency- same behaviours acrross different instances.6. Transparent design- content viewable without interface interfer-ing.

I can use these to evaluate my artefact against and they provide a good measure to test against during my usability testing.

System Ideals (Heuristic)

Usability test

Planning

Usability Study

For my usability tests I ran my app in my development environment and set up a remote desktop with google chrome remote desktop. This allowed me to share my screen to my test participants and let them have control while I observed and made notes. I also recorded the screen using Iris screen recorder so that I could refer back to any particular scenarios to see how each task was handled.

I carried out the tests with 4 users, 2 for each role from my target de-mographic. I timed how long each task took and how many failures they had along the way. After watching them complete the tasks I asked them a series of follow up questions and informally asked for their opinions and any other comments they had about the experi-ence. I noted down key responses and then synthesized common or recurring problem themes and any notable roadblocks in the walk-through and pitfalls in the design noted from their feedback.

During the walkthrough I made lots of notes and observations which I then analysed to try and figure out why users were having prob-lems and what possible fixes and solutions there could be, or dif-ferent implementations that may be more effective. I looked at the users mouse movements and asked them afterwards in the followup if there were any parts that they found frustrating or confusing. All of the results from my usability test were then compliled into a com-plete set of findings which provide answers to my initial questions.

User Interactions Analysis

Page 41: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

38

Usability study findingsI discovered a lot more problems than expected during the usabil-ity test, helping me to uncover lots of issues that I had overlooked in development. Some issues were technical, but the majority had to do with the system language and functionality of the app. I also found that users interacted with the app differently than I had ex-pected, taking different routes and helping me to identify where more feedback or clearer functional labelling or indication was required.

I have broken down the findings and for each feature or aspect, given any positive or negatives from the study aswell as what it has helped me to learn about the system to make ammendments.

Creating an account- This took much longer than I was expecting for 2 of the users who did not notice the register button. Becuase logging in is the defualt form state, not signing up, 1 of the users first incorrectly entered their details in the log in form. I can either increase the text size of the link to make it more prominent, or rede-sign the form so that a user can enter their email address first and then click next to proceed to either log in or sign up.

Post a job- Firstly I discovered a technical issue with the styling of the page as I watched the first user click on the <select> element but without the event registering. I think something in my CSS was causing the header to sit above the box making it unclickable. I knew this worked at a smaller screen size so I changed the viewport for them and continued.

All candidates were able to successfully post a job, however there was some confusion on the job form. When trying to add experi-ence, one of the users entered multiple values in the same field rather than clicking the add button to add another field. While there is no real harm in this, the stored values would be easier to manipu-late as seperate values so I think adding a prompt to say “add new skill” next to the add button and ensuring that the button appears BELOW the new field would help. Another user mentioned that the remove button wasn’t very clear and it was only by experimenting and clicking it that they realised its function. They also said they would have liked a warning before it being deleted.

Add a profile- This task caused some unexpected difficulties as it was not easily understood and I had to be asked for help by one of the participants. They assumed that adding a profile would add some kind of secondary user profile to their account/ rather than its actual function of adding additional additional information. The language used may be confusing to some users so changing it to a differnt call to action like “Add a bio” or something similar would make the functionality more apparent. One user also commented they would like to be able to add a photo, a feature I would like to imlement but did not have time to within the timeframe of the pro-ject.

Apply for job- All users easily managed to apply for a job, but maybe too easily. After watching the users and then asking about it afterwards, it seemed like they thought clicking the apply button was going to give the some kind of confimation dialogue before send-ing, but the application is sent straight away. I think an intermediary interface would be useful here, which could also be used to allow users to perhaps add a cover letter or message to their application.

Send a message to a nearby user- All users were able to send a message easily, but one user commented that there was no way to just instantly send a job offer to a user without them applying first. This is somehting I would like to achieve. It takes some extra work as users can have multiple job postings I would need to create an interface that allows them to select which job they are sending the offer for.

Check how many applicants a job has- When asked to do this, ALL of my users went straight to the off canvas navigation and went to the my Jobs page. This page was really meant to track active jobs, but should really be updated to include a better overview all jobs. Noone used the my jobs link on the homepage which provides a summary of the jobs, but eventualy found the same information in the jobs page by cliking into the accordion. Users found the accor-dion confusing and said they would prefer if all of the job data were styled in the same way.

Another issue with the my jobs page was confusion between “open” and “active” jobs. They sound as though they are the same thing so a better standard name for these should be applied to give users a clearer indication of the job status.

Respond to a job application with a message- This test went smoothly but it was noted that the recieving user would have no way of knowing that the user was the owner of the job unless specified. Adding a job ref to outgoing messages would help keep the user informed.

Apply to a job from the list view- Users liked the list view but one user said it wasn’t that obvious that the label for the toggle button was associated with the button, and that the control could be clear-er.

Leave a rating for a user- This test provided some interesting results, as users intuitively navigated to either the profile or to the homepage to click on the my jobs link. This does currently show completed listings but there is no way to rate from here. A better solution would be to keep this link for open jobs, and then have completed jobs stored on the jobs page. There should then be an additional job state called “unrated” so that users could see all the jobs with users they still need to rate , rather than completed jobs going straight to the completed section.

Usability study evaluationThe usability study proved to be really helpful in identifying flaws in the UI which I had become so accustomed to in development that I did not notice. Updating system language accross the app and providing better feedback were two key takeaways to get my app in line with the system heuristics. As well as the flaws, users generally found the app very useful and said it was a really cool and quick way to find work.

2.2 Technical evaluationIn order to evaluate the technical successes and failures of my artefact, I can assess whether my implementation has kept in alignment with my technical and functional spec-ifications. As well as this, I can look at the quality of the code, and how well it performs and if the artefact meets all of the aims and onjectives which I originally specified.

Interfaces gives a solid level of feedback throughout, keep-ing the user in the know as to the system status at all times. This is a very important aspect of the designs. Almost most actions every action is catered for by a response, avoiding errors with good example default formats (eg. live search function). Provide an intuitive order of events for the user to progress through the site. The site features a minimalistic design throughout and through use of colour and type face I hope to create a sense of professionalism with the smooth technical animations for example.

Page 42: Project Title: Ready to work · I can use DDP to update my users location in real time, aswell as display messages between users instantly and update user and job records for all

39

2.3 Conclusion

To conclude my evaluation, I can look back at my origi-nal plan, aims and objectives and see how well my final artefact realises those aims, as well as if there could have been any better routes to their realisation. Looking back at the plan and development with the power of hindsight also allows me to identify alternative paths. Where the goals have been achieved I can see if there could have been any better ways to achieve the goal.

Overall, the platform does provide all of the functionality and is succesful in providing a real time service to users. The fact that it updates instantly is a real bonus and I would not change this part of the development. However, this could be built on and improved in a number of ways from what I have learnt not only through my testing and feedback, but through the experience and knowledge I have gained thoughout the project.

One thing I could have definitly improved in my workflow was my file organisation. The structure of the app is a bit all over the place and while I planned to seperate into seperate files for each function this never happened as I got carried away with other code. Also, adding proper schemas to my database collections.

The original aim of broadcasting a job and being shown first responders was implemented but could perhaps be improved in a couple of ways. If, when a user posts a job, all nearby users were alerted instantly and the first to respond automatically added to this shortlist, this could provde a quicker and easier way to confirm a jobn than having to wait for an application or send one.

As a started as a complete beginner in Meteor i picked up a lot of knowledge on the way that would allow me to do things more easily in future, or if I were to do this project again. For example, discovering packages that handle fucntionality that I wrote from scratch was a key lesson. I could have used packages like aldeed:autoform to add forms which automatically insert into my collections which would save time and effort.

There were a couple of features I was unable to imple-ment due to time constraints which I would include to make the artefact more useful. These incluide the filters on the map, calendar and a way to upload a CV. I have tried to follow guidelines and principles on user interac-tion, considering how the typical user will use my site.

While I have been fairly critical during the review, mainly highlighting the flaws , overall I am still very happy with the result. I took on an ambitious project and managed to make a working solution that completes most of the aims and objectives, albeit a little incomplete in places. I am keen to continue developing the app for the final exhibi-tion and with a complete overhaul of unnessecary or con-fusing features, plan to make the artefact into a compete, robust solution that could go into produciton.