Blog Post

Developer Blog
6 MIN READ

How We Built It: User Profile Hover Card

JavidH's avatar
JavidH
Khoros Staff
3 years ago

Overview

User Profile Hover Card is used to display user information such as pronouns, roles, number of posts, kudos, and solutions. With the User Profile Hover Card, you see user information while viewing any article in your community by hovering your mouse cursor over either their avatar or the user name.

Note: The User Profile Hover Card will not be displayed in the user profile.

A JavaScript function will be attached to certain elements on the page that makes an AJAX call to the server when the mousenter event is triggered. This AJAX call request will return all the information necessary to display a hovercard with the user profile information.

You can create a Profile Hover Card using these three steps covered in this guide.

  1. Building an endpoint
  2. Creating a custom javascript function
  3. Adding a javascript function to a quilt to display the user information

Here is an image of the User Profile Hover Card in Atlas Community:

Building the endpoint

Create a new endpoint in Studio named profile-card (Studio > Endpoints > New Endpoint). Here is the overall structure of our code. After some initialization code and setting up some variables, we have two main steps outlined in the comments.

 

 

 

 

<#compress>
<#-- Set up number format and import some functions you will use later on -->
<#setting number_format="0.######"/>
<#include "theme-lib.common-functions" />

<#-- The user whose profile information we would like to display -->

<#assign userId = getRequestField("userId", "-1", true)?number />
<#assign unqId = getRequestField("unqId", "")?string />
<#assign badgeSize = 5 />

<#if userId gt 0 && validEndpointRequest(false, true,false)>
<#-- Step 1. Make REST call for the data required for the component -->
     <#-- . . . see below code snippet . . . -->

  <#-- Step 2. Render the actual card markup -->
     <#-- . . . see below code snippet . . . -->
  </#if>
</#compress>

 

 

 

 

Step 1

To fetch the user’s profile information, we just need to write a LiQL request and make the request assigned to a variable.

 

 

 

 

<#assign userQry = "SELECT login, view_href, rank.name, rank.color, user_badges FROM users WHERE id='${userId}'" />
<#assign userProfileData = executeLiQLQuery(userQry) />

 

 

 

 

Step 2

In step 2, we will use the data we just fetched to create some variables and return the markup required for the hovercard.

 

 

 

 

<#if userProfileData?size gt 0>
		<#assign userProfileData = userProfileData[0] />  
        <div>
		<section>
          <span><span id="cardTitle-${unqId}"><a href="${userProfileData.view_href}">${(userProfileData.login)!""}</a></span>
			<span id="cardDesc-${unqId}">${(userProfileData.rank.name)!""}</span>
		</section>

		<#-- display badges -->

		<#if userProfileData.user_badges?? && userProfileData.user_badges.size gt 0>
		<section>  
            <#assign badgeCount = 0 />    
			<#list userProfileData.user_badges.items as userBadge>
                <#if userBadge.earned_date??>
				<div>
					<img title="${userBadge.badge.title}" alt="${userBadge.badge.title}" src="${userBadge.badge.icon_url}">
				</div>
            	<#assign badgeCount = badgeCount + 1 />
				<#if badgeCount == badgeSize>
					<#break>
				</#if>
				</#if>
			</#list>
		</section>              
		</#if>

		<#-- posts, kudos, solutions -->

		<#assign postCount = 0 />
		<#assign kudoCount = 0 />
		<#assign solutionCount = 0 />
		<#assign metricsQry = "SELECT * FROM metrics WHERE user.id = '${userId}' AND id IN ('net_overall_posts','net_accepted_solutions','kudos_weight_given','kudos_weight_received')" />
		<#assign metrics = executeLiQLQuery(metricsQry, false, true) />
		<#if metrics?size gt 0>
			<#list metrics as metric>
				<#switch metric.id>
					<#case "net_overall_posts">
						<#assign postCount = metric.value?number />
						<#break />
					<#case "net_accepted_solutions">
						<#assign solutionCount = metric.value?number />
						<#break />
					<#case "kudos_weight_received">
						<#assign kudoCount = metric.value?number />
						<#break />
				</#switch>
			</#list>  
		</#if>          
		<section>
			<ul>
				<li>${postCount} <span><#if postCount == 1>${text.format("general.Post")} <#else>${text.format("general.Posts")}</#if></span></li>    
				<li>${kudoCount} <span><#if kudoCount == 1>${text.format("general.Kudo")} <#else>${text.format("general.Kudos")}</#if></span></li>
				<li>${solutionCount} <span><#if solutionCount == 1>${text.format("general.solution")} <#else>${text.format("general.Solutions")}</#if></span></li>              
			</ul>                        
		</section>
		</div>
	</#if>
</#if>

 

 

 

 

It looks like a lot of code, but it’s pretty straightforward once you get the hang of it. Now that we’ve got a backend endpoint that can talk to the Community's backend and render markup, we will turn our attention to the client so we can make use of it.

Create a custom javascript function

In Studio > Components > New Component, create a component named custom.profile-card.script. This is where we will attach an event to elements on the page to trigger the hovercard which we wrote in the Building the endpoint section.

We will be using @liaAddScript to insert our jQuery, but first, we need to set up the component by adding some common functions and preventing this script from running if we are on the user profile page.

 

 

 

 

<#include "theme-lib.common-functions" />

<#if page.name != 'ViewProfilePage'>
<@liaAddScript>

<#-- This is where the main javascript will go -->

</@liaAddScript>
</#if>

 

 

 

 

Now we can focus on what goes in between our @liaAddScript tags. We’ll start with an Immediately Invoked Function Expression (IIFE), like any other custom script. Here we’ve got two things to accomplish: first, we need to define a helper function to generate a unique id for the hovercard so we can keep track of it in the backend. Second, we’ll attach mouse events to certain elements of the page to make our AJAX calls.

Note: You will see references to CSS classes that handle animation for the appearance and dismissal of the card. This tutorial does not include styling, but the classes should be named in such a way that you can add animations to them or simply show or hide the element.

 

 

 

 

 ;(function($) {
 <#-- Make Unique Id makeid() : string () -->
		function makeid() {
			var text = "";
			var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

			for (var i = 0; i < 5; i++)
				text += possible.charAt(Math.floor(Math.random() * possible.length));

			return text;
		}

		$(document).ready(function () {
			$('body').on({
				mouseenter: function(evt) {		
				<#-- break out early and don't render the card -->		
					if ($(this).parents('.lia-component-users-widget-menu').length > 0) {
						return;
					}
					if ($(this).hasClass("disable-hovercard"){
						return;
					}

					evt.preventDefault();
					evt.stopPropagation();

					$('.hc-user-profile').removeClass('hc-animate-in hc-is-shown');

					<#-- if the card already exists for this avatar/link, just reshow it (no need to go fetch another one) -->
					if ($('.hc-user-profile', this).length > 0) {
						$('.hc-user-profile', this).addClass('hc-animate-in hc-is-shown');
						return;
					}
					var unqId = makeid();
                    var userId = $(this).attr('href').substring($(this).attr('href').lastIndexOf("/")+1, $(this).attr('href').length);
					<#-- prepare a container for the card we will render -->
					var divContainer = $('<div class="hc-user-profile user-profile-card" role="dialog" aria-labelledby="cardTitle-'+unqId+'" aria-describedby="cardDesc-'+unqId+'"><div class="hc-main-container info-container"><div class="spinner"></div></div></div>');
					$(this).append(divContainer);
					$(divContainer).addClass('hc-animate-in hc-is-shown');
					
					<#-- request to the endpoint we created earlier -->
					<#-- passing back to the userid for our backend LiQL call -->
					$.ajax({
						url: '${getEndpointUrl("profile-card")}',
						type: 'post',
						dataType: 'html',
						data: {"userId": userId, "unqId": unqId},
						beforeSend: function() {},
						success: function(data) {
							$('.info-container', divContainer).append(data);
						},
						error: function() {
							console.log('your error message should go here.');
							$('.info-container', divContainer).append('<div class=""><i class="lia-fa fa-var-close" /></div>');
						},
						complete: function() {
							$('.spinner', divContainer).remove();
						}
					});
				},
				mouseleave: function() {
					$('.hc-user-profile').removeClass('hc-animate-in hc-is-shown');                                
				}                                                                                                        
			}, 'a.lia-link-navigation.lia-page-link.lia-user-name-link,.UserAvatar.lia-link-navigation');
  })(LITHIUM.jQuery);

 

 

 

 

You can see at the end, that we attach the jQuery function to .lia-user-name-link and .UserAvatar.lia-link-navigation. These are the elements that will be hoverable.

Adding the custom javascript function to the quilt

Finally, we will attach the custom script we just wrote to a quilt that is always present on the page: Footer.quilt.xml

 

 

 

 

 <add to="ui-scripts">
   <component id="custom.profile-card.script"/>
 </add>

 

 

 

 

Conclusion

There you have it! A hover action that, when triggered, will make a request to the backend, fetch information about the user in question, and render a user profile hovercard to get quick information about that user.

Updated 3 years ago
Version 1.0
No CommentsBe the first to comment