Creating a multi-step "process" badge

  • By Michael Garrison 11 Months Ago

When our church first started on Rock, we had five classes that we asked new members to take - to introduce them to the church, help them find a ministry, etc. This is a pretty common process, and the question always comes up how you should keep track of where people are in the process.

Some churches have a group for each class, and add people to the group when they've completed a class. To determine whether a person has taken a class, you just check for their membership in that group.

Some churches have a person attribute for each class, which gets filled in (frequently with a date) when they complete the class. To determine whether a person has taken a class, just check for the corresponding person attribute.

Both of these approaches have their benefits and their drawbacks. But no matter which method is chosen, the next question that frequently arises is, "How can I tell at a glance where a person is in the process?"

You can certainly create a badge for every class, but that can lead to a lot of clutter on the badge bar.

Our church chose to create a single badge that showed all of the items in an unmistakable, but compact, way.


Let's start off with the final rendered HTML codes for a badge on a person who have completed classes 1 and 2, but not 3-5:

This is accomplished with the following HTML:

{% capture tooltipText %}This person has taken:<br />Class 1 on 1/1/2018<br />Class2 on 1/2/2018{% endcapture %}
<div class="badge" style="position:relative;" data-toggle="tooltip" data-original-title="{{ tooltipText }}">
    <i class="badge-icon fa fa-road" style="color:#000;"></i>
    <i class="fa fa-check-square-o alert-success" style="cursor:default;position:absolute;size:20%;left:0%;bottom:0px;"></i>
    <i class="fa fa-check-square-o alert-success" style="cursor:default;position:absolute;size:20%;left:20%;bottom:0px;"></i>
    <i class="fa fa-square-o alert-danger" style="cursor:default;position:absolute;size:20%;left:40%;bottom:0px;"></i>
    <i class="fa fa-square-o alert-danger" style="cursor:default;position:absolute;size:20%;left:60%;bottom:0px;"></i>
    <i class="fa fa-square-o alert-danger" style="cursor:default;position:absolute;size:20%;left:80%;bottom:0px;"></i>
</div>

Straightforward enough! We create a div element with position:relative (which just tells all of the elements within it to set their positions according to it's boundaries rather than the page's). Then we use one Font Awesome icon as the background, with the badge-icon class (which sizes it to match the rest of your badges). Finally, the checkboxes themselves are created with other Font Awesome icons.

If you want something besides a road as the background icon, the easiest solution is to find another Font Awesome icon. Here's the same example, but using badge-icon fa fa-bicycle as the class in the second line:

Easy!

If you want only four checkboxes instead, size them to 25% (100% / 4) instead of 20% (100% / 5) and increase the "left" position of each one by 25% instead of 20% also. If you want 6, use 16% for size and left position, etc.


Okay, but this isn't dynamic; it's just a static sample of the codes we WANT to end up rendering for each person.

That's fine; it's helpful to start with your goal and then replace the static parts with dynamic lava as we develop it.

Install the badge

So start by creating your Lava-type badge and copying in the codes for the badge you want to end up with. Save it, then visit a person profile and add the badge to the badge bar where you want it to end up. Make sure it looks right before we start wiring up the functionality.


Now that it looks right, go back to your badge definition. We're going to create some Lava variables for each of the classes you're interested in.

If you have one group for each class, you'll need to add a series of lines at the top of your badge's lava like this:

{% assign class1 = Person | Group: "29" | Property:'DateTimeAdded' %}
{% assign class2 = Person | Group: "30" | Property:'DateTimeAdded' %}
{% assign class3 = Person | Group: "31" | Property:'DateTimeAdded' %}
{% assign class4 = Person | Group: "32" | Property:'DateTimeAdded' %}
{% assign class5 = Person | Group: "33" | Property:'DateTimeAdded' %}

This will set each variable to the date they were added to the group if they've taken the class. Otherwise the variable will stay blank. (Of course, you'll have to change these GroupId numbers I wrote in red to match your actual class GroupIds)

Whereas if you use a person attribute for each class, these are the lines you'll need to add to the top of your badge's lava instead:

{% assign class1 = Person | Attribute:'Class1Date' %}
{% assign class2 = Person | Attribute:'Class2Date' %}
{% assign class3 = Person | Attribute:'Class3Date' %}
{% assign class4 = Person | Attribute:'Class4Date' %}
{% assign class5 = Person | Attribute:'Class5Date' %}

Once you change the attribute key (the text in red) to match your actual class attribute keys, you'll likewise have a series of either blank values (if they didn't take the class), or dates (for the classes they've taken).

Just because this is a great example, it's worth mentioning that one benefit of using the Person Attribute method of storing the data, is that you can set the date to an arbitrary value, rather than having to rely on DateTimeAdded (or creating a groupmember attribute to store a date).

Now we've got the data!

Wire it up

We're going to wrap each of your checkboxes in a conditional tag now, to render them differently based on the data.

So, each of your checkbox lines will be preceeded by {% if class1 != empty -%}, and have two conditions. Here's a typical example, using class1:

{% if class1 != empty %}
    <i class="fa fa-check-square-o alert-success" style="cursor:default;position:absolute;size:16%;left:0%;bottom:0px;"></i>
{% else %}
    <i class="fa fa-square-o alert-danger" style="cursor:default;position:absolute;size:20%;left:0%;bottom:0px;"></i>
{% endif %}

So you can see that we've changed which Font Awesome icon we're using for each box (fa-check-square-o versus fa-square-o) and used a different alert class to set the color (alert-success versus alert-danger), based on whether our variable is empty or not (remember, it's empty if they haven't taken the class).


One bit remains static: the nice tooltip which should indicate which classes have been taken when the user hovers over the badge is still hard-coded and doesn't reflect the actual data. Replace the dummy {% capture tooltipText %} line from our template Lava with this:

{% capture tooltipText -%}
    {%- if class1 != empty or class2 != empty or class3 != empty or class4 != empty or class5 != empty -%}
        {{- Person.NickName }} has taken:{{- -}}
        {%- if class1 != empty %}<br />Class One on {{ class1 }}{% endif -%}
        {%- if class2 != empty %}<br />Class Two on {{ class2 }}{% endif -%}
        {%- if class3 != empty %}<br />Class Three on {{ class3 }}{% endif -%}
        {%- if class4 != empty %}<br />Class Four on {{ class4 }}{% endif -%}
        {%- if class5 != empty %}<br />Class Five on {{ class5 }}{% endif -%}
    {%- else -%}
        {{- Person.NickName }} has not taken any classes.{{- -}}
    {%- endif -%}
{%- endcapture %}

If you haven't run into it before, the dashes we've added on the inside of our Lava tags may be confusing. Here's the secret: if you use {%- or {{- as the opening to a lava tag or output, it means "delete all whitespace including linebreaks before this tag". And likewise, if you use -%} or -}} at the end, it means "delete all whitespace including linebreaks after this tag". Since we need our tooltip to all be rendered on a single line in the HTML, we're using this method so we can format our conditionals in a sane manner in the Lava, but have just a single line come out at the end.

Oh, in case it isn't obvious, you should replace the names of the classes with the names your church has given your classes here - I highlighted the text you should change in red again =)

Now we've got a nice tooltip all wired up and ready to go.


In fact, our badge is now finished!


Here are the final Lava Badge codes, using the attribute method. Just remember to use your actual Attribute Keys on lines 1-5 and to change the name of your classes on lines 10-14:

{% assign class1 = Person | Attribute:'Class1' %}
{% assign class2 = Person | Attribute:'Class2' %}
{% assign class3 = Person | Attribute:'Class3' %}
{% assign class4 = Person | Attribute:'Class4' %}
{% assign class5 = Person | Attribute:'Class5' %}
{% capture tooltipText -%} {%- if class1 != empty or class2 != empty or class3 != empty or class4 != empty or class5 != empty -%} {{- Person.NickName }} has taken:{{- -}} {%- if class1 != empty %}<br />Class One on {{ class1 }}{% endif -%} {%- if class2 != empty %}<br />Class Two on {{ class2 }}{% endif -%} {%- if class3 != empty %}<br />Class Three on {{ class3 }}{% endif -%} {%- if class4 != empty %}<br />Class Four on {{ class4 }}{% endif -%} {%- if class5 != empty %}<br />Class Five on {{ class5 }}{% endif -%} {%- else -%} {{- Person.NickName }} has not taken any classes.{{- -}} {%- endif %} {%- endcapture %}
<div class="badge" style="position:relative;" data-toggle="tooltip" data-original-title="{{ tooltipText }}"> <i class="badge-icon fa fa-road" style="color:#000;"></i> {% if class1 != empty %} <i class="fa fa-check-square-o alert-success" style="cursor:default;position:absolute;size:16%;left:0%;bottom:0px;"></i> {% else %} <i class="fa fa-square-o alert-danger" style="cursor:default;position:absolute;size:20%;left:0%;bottom:0px;"></i> {% endif %} {% if class2 != empty %} <i class="fa fa-check-square-o alert-success" style="cursor:default;position:absolute;size:20%;left:20%;bottom:0px;"></i> {% else %} <i class="fa fa-square-o alert-danger" style="cursor:default;position:absolute;size:20%;left:20%;bottom:0px;"></i> {% endif %} {% if class3 != empty %} <i class="fa fa-check-square-o alert-success" style="cursor:default;position:absolute;size:20%;left:40%;bottom:0px;"></i> {% else %} <i class="fa fa-square-o alert-danger" style="cursor:default;position:absolute;size:20%;left:40%;bottom:0px;"></i> {% endif %} {% if class4 != empty %} <i class="fa fa-check-square-o alert-success" style="cursor:default;position:absolute;size:20%;left:60%;bottom:0px;"></i> {% else %} <i class="fa fa-square-o alert-danger" style="cursor:default;position:absolute;size:20%;left:60%;bottom:0px;"></i> {% endif %} {% if class5 != empty %} <i class="fa fa-check-square-o alert-success" style="cursor:default;position:absolute;size:20%;left:80%;bottom:0px;"></i> {% else %} <i class="fa fa-square-o alert-danger" style="cursor:default;position:absolute;size:20%;left:80%;bottom:0px;"></i> {% endif %} </div>


P.S: Want to use an image instead of a font awesome icon as the background? Here's the new lines 20-21:

<div class="badge" style="position:relative;background:url('/link/to/my/badge.jpg') no-repeat center; background-size:contain;" data-toggle="tooltip" data-original-title="{{ tooltipText }}">
<i class="badge-icon fa fa-road" style="color:transparent;"></i></div>

Don't worry; the road won't show up; we're just using it to keep the badge sized correctly.


@mikejed
Spark Development Network
Flagstaff, AZ

Michael Garrison recently left his job in Architecture to become one of the "new guys" at Spark (the "Core Team"), but he's still helping out Christ's Church of Flagstaff and other non-profits with tech needs in his off-hours, trying to make computers do what computers do best, so that people are freed to do what we do best: relate with people!