Programming

Getting stuck into design

While I consider myself a ‘full stack’ developer, taking care of everything from the back end to the front end of town, one area that I tend to lack is in my design skills. I am trying to learn more about good graphic and user experience (UX) design principles, so that I can improve the software I write without having to resort to a third party expert every time.

What better way to start than with my flagship SaaS HR product, which is in use by over a thousand people all over the world? Looking at the stats on Google Analytics, I see that the most common screen used on my app is the employee Leave Request screen, which employees of our customers use to ask for time off from their managers.

While we haven’t really heard any real complaints about this screen, I knew we could make it easier for people to use, without too much effort. Here is the original screen:

Employee_Leave_Request_OLD.png

I thought the blue bordering on this screen made it look a little dated. Plus the title at the top which says “Request Leave or Time Off” seems a little disconnected from the rest of the screen. Lastly, the one bit of feedback we’ve heard from employees was that they would like to see the company leave calendar on here which was useful to them when planning time off.

So, I sat down for a morning, and reworked the screen to remove the borders, and make it look more like a plain paper leave application form:

I removed the top title as it was redundant, and removed the borders around the window. I also squashed the main form down a little to increase white space around it and make it look more like a paper form that the employees would have been used to filling out before.

I also removed a lot of extra words within the form (i.e. the help text below each field) and made them popups that would appear when the user clicked on the ‘?’ icon above each field. Just to make things cleaner and have less word clutter.

At the bottom of the screen, you can see where I have ‘squished’ the old list of leave balances down, which is still readable, and added the company leave calendar to the system.

After some initial testing, I made some finer touches for the final version:

Employee Portal Leave.png

Not much that is immediately obvious, but they did make the form seem aesthetically better. I fixed the alignment of text across the form, plus I added a background colour to the form fields themselves so they stood out a little and didn’t make the form look so washed out and overly white.

What do you think? We actually saw an uptick of activity on this form already this week since we put out the update to production, and so far no one has emailed in to complain about anything, which is a good sign IMO.

Because I am all about constant learning and improving, I would love to hear from some experienced designers out there as to how I could make things better.


Building a HelpScout sidebar widget

We recently moved our support system for our HR SaaS over to HelpScout, predominantly as a cost saving exercise. So far our support crew is loving HelpScout, however there were a few key things missing compared to our old support system - mainly extra information about our customers, such as the current plan they are one, and when their subscription expired etc, which were pushed to our old system via API calls.

We investigated HelpScout’s API infrastructure, which was powerful, but would come at an extra cost based on number of users, which was going against our plan to save costs. But then, while perusing the HelpScout documentation, I noticed that they had the ability to add your own custom sidebar widget to the communication screen. No API needed! This sounded perfect.

More digging, and I found out that HelpScout can actually send a WebHook to any address when the communication screen is opened. This is done via a Dynamic App, and the process is explained on their developer website on this page.

In essence, when you open a conversation with a customer, HelpScout will send a packet of information back to your app with the customer details (including their email address), and all your app needs to do is to send back a pre-formatted HTML snippet with any customer information that you think will be useful for your support team to know.

Here is the sidebar on our HelpScout conversation page, showing the information that we pull and can view while talking to our customer:

Ta Da! Our HelpScout mailbox page now has useful info on the right hand side!

Ta Da! Our HelpScout mailbox page now has useful info on the right hand side!

As you can see on the sidebar (on the right hand side), we show the company name that this user registered in our HR system, and the date that their current plan expires. We also show things like the timezone that the user (and the company) have set up, and the number of employees they have versus the limit of employees they can have on their current plan. We also show their Stripe identifiers (in case we need to lookup their account details in there) and the modules that they have activated in our HR system.

This helps us to answer the common questions, such as “When is my subscription renewal due?” or “How many employees can I have on the system?” without having to leave this screen.

Oh, and under the company name we also show a couple of badges that denote whether this user is the ‘Owner’ of the company (i.e. the person who set it up and is paying for it on their credit card), and also whether this company is currently on a paid subscription or in trial mode, or is an expired trial (Yes, we provide support to customer in trial mode!).

In the middle section there, you can see that HelpScout gives us other useful information such as the browser and operating system that the user is using.

How do we set this up? Well, it is actually quite easy and straightforward. Here is a step by step (taken from our own system, which took a couple of hours to set up). Note: You have to be on the HelpScout Standard or Plus plan for this to work, it won’t work on the Basic plan.

Step 1: Set up a custom app in HelpScout

Click on ‘Manage’ then ‘Apps’ from your HelpScout main dashboard.

HS_Setup_01.png

Then scroll down to the bottom of all the apps on this screen and choose ‘Build a Custom App’

HS_Setup_02.png

Now click the ‘Create App’ button on the left.

HS_Setup_03.png

Fill in the following fields (explained below the graphic).

  • App Name - can be anything you like but I would suggest calling it the same as the app you are linking to.

  • Content Type - make sure you change this to ‘Dynamic Content’.

  • Callback URL - This will be the URL we will create next, that HelpScout will call to extract the data from your app.

  • Secret Key - This is the confidential key that HelpScout and your app will use to verify that the callback above IS in fact being called from HelpScout and not via some nefarious infiltrator trying to steal your customer information. Make sure you use a hard to guess key (Tip: I highly recommend using RandomKeyGen to create one for you to choose from).

  • Debug Mode - Leave this off for now.

  • Mailboxes - Nominate the mailboxes in HelpScout that the customer information will be sent to (i.e. you may want it in your Support chat windows that are triggered by your paying users, but not on your Website chat box where your sales team talks to leads not in your system.

Hit ‘Save’ to save this custom app to your HelpScout system.

Step 2: Create the webhook endpoint in your app

Ok, now head over to your app to create the endpoint that HelpScout will call whenever you open the nominated Mailbox communication screen.

I will show you the snippet from our own website, which uses Ruby (not Rails, but rather a Sinatra based DSL framework).

HS_Setup_05.png

The concept is pretty much the same in any language, and I will step you through the various stages.

Line 1 is setting up a POST endpoint called ‘/sendinfotohelpscout’ - this is the same name endpoint as we set up in the ‘Callback URL’ in Step 1 above. Note that this has to be a POST handler, and not a normal GET handler. Note also above that we had to nominate to turn OFF cross-site protection via the ‘csrf_protection => false’ flag. This is because we don’t normally allow external sites from our own domain to POST information to our app for security purposes, however in this case, we have to allow HelpScout to post to this particular endpoint.

Line 2 is calculating the SHA1 signature hash of the body contents received in this request, using the same ‘Secret Key’ as we set up in Step 1 above. Note that for best practice, we store the secret key in an environment variable called ‘HELPSCOUT-SIGNATURE-KEY’ rather than embed it in our code.

Line 3 then compares the signature (which is sent by HelpScout is a request header field called ‘HTTP-X-HELPSCOUT-SIGNATURE’) with the one we generated above. If they match, then we know that this is a legitimate POST from HelpScout, if they don’t, then we can safely ignore this request and jump straight to Line 15 where we return a 403 (Unauthorised) response.

Line 5 tells our app to return any content generate as a JSON file rather than HTML. Then Line 6 extracts out the JSON data that is posted to our system so that we can parse the customer’s email. Here is a sample of the JSON packet that is sent to our app from HelpScout.

ticket: {
   id: 12345,
   number: 56789,
   subject: "Help me!"
},
customer: {
   id: 54321,
   fname: "Fred",
   lname: "Smith",
   email: "fredsmith@mailinator.com",
   emails: ["fredsmith@mailinator.com"]
},
mailbox: {
   id: 87654,
   email: help@domain.com
}

The bit we are after is in ‘customer -> email’, so in Line 8, we try and fetch a record from the User data table where the user’s email is contained in this JSON field. Note: You can find by other information such as the user name or ID, but in our case, the Email address of the customer is a unique field in our User table, so we used that.

If we successfully find the user, then we return the sidebar HTML snippet in Line 10, otherwise we send back a ‘Not found’ message in Line 12.

Please note that the returned HTML or error message has to be contained within a JSON message like:

{"html": “This is the return error or HTML stream”}

That’s it for the Callback endpoint - only 17 lines of code!

Step 3: The sidebar snippet

You can see in the code snippet in Step 2 above that if the User is found in our system via their email, then our app renders an HTML snippet called ‘integrations/third-party/helpscout-feed’. This is not an entire HTML page, but rather a small snippet consisting of <UL> and <LI> directives. Here is a shortened example of an ERB script to generate the snippet:

<ul class="c-sb-list c-sb-list--two_line">
  <li class="c-sb-list-item">
    <span class="c-sb-list-item__label">
      Customer Since
      <span class="c-sb-list-item__text">
        <%= @user.signup_date.strftime("%d/%m/%Y") %>
      </span>
    </span>
  </li>
  <li class="c-sb-list-item">
    <span class="c-sb-list-item__label">
      No. of Employees
      <span class="c-sb-list-item__text">
        <%= @user.employee_count %>
      </span>
    </span>
  </li>
</ul>
<% if @user.trial_expired? -%>
    <span class="badge yellow">Trial Expired!</span>
<% end -%>

Don’t worry too much about the various CSS classes on here such as ‘c-sb-list’ or ‘c-sb-list-item’ etc. These all affect how the information will be displayed in the sidebar, and are explained in full on this page. And remember that we don’t need the <HTML> or <BODY> etc. tags wrapped around this snippet, so please be sure to generate a partial snippet that doesn’t use your default site application layout. (You can see in our code above that we specified the :layout => false directive in line 10 which prevents the system from wrapping the snippet in the application look and feel.

Feel free to embed whatever customer information you would like in the snippet. You can even create collapsible sections, and use icons. See the Advanced Style Guide Components for the CSS classes that you will need to do this.

That is it! Once you have saved and deployed the new chunk of code for the endpoint (and the ERB snippet that it returns) to your server, you should be able to open a conversation from one of your users, and your sidebar should be populated like ours is right at the top of this post.

Do you have any creative ideas as to how we can present information on this sidebar? If so, I would love to hear from you in the comments below!







Doing Support Wrong

Photo by  Jonny Caspari  on  Unsplash

I remember when I set up my software consulting business over 25 years ago, my business partner and I wanted to differentiate ourselves from our competitors in town in dramatic fashion. So to try and achieve that, we decided that we would provide incredible support to our clients, which included making ourselves available to them at any time during the week that they needed us. And I mean any time - we sent out letters to them stating that they could call us on a Sunday night when their server went offline, or even on public holidays.

And guess what? They did just that.

At first, this excited us - our customers were taking advantage of our superb support offering, which was building loyalty and value. But then, we despaired, because customers were taking advantage of our offering as we had asked them to do.

You see, when the two of us were starting out and only had about 20 customers, the demands on our time were minimal - we would probably get only a single after hours call per week which we would take turns at responding to. But as our reputation grew and others heard about our ‘overtime’ service, we soon found that we couldn’t scale such a promise.

Calls would come in so frequently during the weekend and in the evenings, that we began to resent our clients instead of celebrating them. What is worse, is that our early clients began to just expect that we would be available to them at any time, and changing that preconceived expectation was nearly impossible once set. Any mention of reducing after hours availability was met with a “Oh, now you got successful off our backs, you are abandoning us??” type response.

It was hard. To make matters worse, we also promoted (to our early clients at least) that we would only charge a minimal extra surcharge for after hours service. This increased the resentment factor because we weren’t really making any extra revenue in return for missing out on family dinners etc.

Wind the clock forward to a couple of years ago when I was setting up my new SaaS business, I fell into the same trap again. I set up our support system so that notifications would be sent straight through to my phone and I was determined to answer emails within minutes, not hours as some of my (much larger) competitors did.

But alas, we ended up having more customers for our SaaS outside of Australia. Mainly in the US and Canada actually, which is the opposite side of the clock from me. Thus began the flurry of support emails coming through at 2am in the morning. Goodbye restful sleep!

What is worse is that our support chat widget on our site had already been ‘trained’ by my existing quick response time, so it would tell any new customer to expect a response “within a few minutes”. So of course, the added pressure was on me to wake up and respond to those requests in order to maintain this epic metric.

Luckily, in this instance, I managed to mitigate the problem by welcoming remote team members in different timezones to my business, so now we can still provide fairly exemplary service to our customers which is NOT detrimental to my own health or sanity.

To anyone else out there setting up a new business which requires providing help to customers, I urge you not to go overboard too quickly. Take a look at your current team size and customer locations, and work out whether instant support any time is actually doable. Also, I am sure that if you speak to your customers, most of them will be willing to wait at least a few hours for help. Unless you are of course selling something that is linked to vital emergency response - waiting won’t kill anyone. In some cases, customers will actually value you more if they don’t get an instant response.

Having an intelligent support system that can evaluate the urgency of the request and escalate accordingly is also useful. In fact, the first support person I hired in my new business - that was their job! Not to actually provide support per se, but purely to be there to take the customer message and say “Thanks for contacting us about problem ‘x’, we have escalated your issue to our technical team.” They knew my sleep patterns and so could even give the customer an accurate response time, i.e. “Someone from the developer team will get back to you in 3 hours”. In a lot of ways, setting up new customer expectations this way worked very well for us. No one got angry or left, and we still got 5 star support rating because we managed expectations well.

Do you have any tips for maintaining great customer support while maintaining your sanity and preventing burnout? If so, I would love to hear from you in the comments below.

My Coda 'Makers Festival' entry

coda_maker_fest.png

I’ve been using Coda in my startup HR Partner for the past year or so, and love the fact that I can create custom dashboards to share and manage data with my team. This week, I noticed that Coda and ProductHunt were having a Makers Festival (No Code Edition) that was pretty cool, and so I thought I would whip up a little mini project in a couple of hours.

The choice of project was a little tricky, but then I remembered that I always wanted to build a mini app to track my liquid intake throughout the day. I have a terrible habit of not drinking enough to keep myself hydrated, and I promised myself that this year, I would improve upon that. What better way that to build a dashboard that would objectively show my how well (or badly) I was doing.

To that end, I decided to build this ‘Waterboard’ app in Coda:

Screen Shot 2019-03-24 at 11.11.14 am.png


This is a very simple app that shows me how I am tracking as far as liquid intake for the day, plus show my trends over the past week.

Here is a breakdown of the app:

At the top of the dashboard, I can set my target goals that I want, meaning the total quantity of liquid that I want to drink every day, plus the time interval between when I take drinks.

Using Coda’s slider widget to set my goals.

Using Coda’s slider widget to set my goals.

If I am below my target quota for the day, the dashboard will prompt me to keep going, and when I exceed the quota, I will get a ‘well done’ message. Similarly, if I go over the time interval set, then the system will warn me that I am overdue for a drink, otherwise I get a thumbs up. Here is what those displays look like in the middle of the page:

Not so good, I am behind in my target quota and it has been a long time between drinks!

Not so good, I am behind in my target quota and it has been a long time between drinks!

And here is the display when I am doing well:

Everything is just ticketyboo!

Everything is just ticketyboo!

Notice also that in this section, I am using Coda’s Rectangle() function do draw in a progressive bar chart which visually shows me my current liquid intake vs the target goal. Makes it easier to see how I am progressing versus trying to do mental maths when I am dehydrated.

The table in the middle of the screen is the actual Coda data table that holds the information on my liquid intake. A really simple table with 4 fields in it:

Coda_Makers_Festival_Entry_5.png

Really, all I am doing is collecting the time of the log entry, the type of liquid (which is a customisable drop down list) and the quantity in ml. The last column is an auto calculated icon that shows me whether the entry was pure water, or a compound liquid like coffee/tea etc. We all know that pure water is best!

Oh, and this table only shows the entries for today. All previous entries are filtered out using Coda’s filter capability in order to reduce clutter.

But seeing as I am a programmer, I hate doing long form data entry. And seeing that my daily liquid intake is usually from one of about three or four different containers, I thought to make up some ‘Quick Hits’ buttons just above the table:

All my favourites. (except Coke - I don’t drink Coke!)

All my favourites. (except Coke - I don’t drink Coke!)

So now just one click will populate the table data with the most popular beverages I drink on a daily basis.

Setting the button action.

Setting the button action.

You can see above how easy it is to set an action to the buttons - I simply nominated that I wanted a click to Add a row to the data table, and I specified the two critical fields that relate to this button (Note that the entry date and time are auto populated using calculated fields within the table itself).

Voila! That is it.

Last on the page is a graph of the past week’s liquid intake, so I can see how I am trending over time:

A veritable roller coaster.

A veritable roller coaster.

That is it. Perhaps about two hours work to put this together, and most of that time was spent looking up the formula syntax for Coda’s date/time and string manipulation.

One downside of Coda is that all timestamps (such as those returned by the Now() function) are in Pacific Time, rather than UTC or local time. Date functions however seem to be in UTC which is strange. Nevertheless, Coda has the concept of Named Functions, so I created a custom function called NowLocal() which converted the returned timestamps from Pacific Time to Australian Central Standard Time.

Coda’s named functions make reusing repeated long formulas so easy.

Coda’s named functions make reusing repeated long formulas so easy.

Where does the 0.6875 come from? Well, Pacific Time is 16.5 hours different from Australian Central Standard Time, so 16.5/24 gives you 0.6875 which is the amount we have to add to the datum to correct the time to my local timezone.

I also created a function called DateLocal() which is basically:

Chaining named functions.

Chaining named functions.

which corrects the Today() function in Coda and returns the correct date for today once adjusted for ACST. See how simple it is to use Named Functions to save typing out the same formulas repeatedly all over the dashboard? In fact, I used several named functions in this dashboard to save time.

Here is an example of using DateLocal() in the graph filter:

Coda supports some quite complex formulas, including IF statements etc. The following formula picks out the last drink time of the day (and returns a sad face emoji if there are no entries for the day). Note copious use of Named Functions to avoid long winded formulae:

Coda_Makers_Festival_Entry_13.png
Waterboard running in the Coda app in iOS.

Waterboard running in the Coda app in iOS.

And yep, it even works in the Coda app to look just like a native iOS app (If you look at the image on the right). I realise that I still need to do some rejigging of a few of the widgets and buttons to make the ‘sit’ properly on the smaller form display, but overall, it is a useful way to use the dashboard and logging too.

TODO: I’d probably add some automation so that a Slack message or notification is sent whenever a drink entry is made. However what I would really like is for a notification to be sent when I am overdue for my next drink, but I don’t think Coda has the ability to send a notification on a formula at this stage.


I am happy to share this dashboard with anyone else out there who is interested in learning how it is built. Feel free to poke around the formulas and functions, and improve/customise it to your liking. Drop me a line if you want a Share link to this dashboard.