Development
...
PulseChecks - Done
PulseCheck - Done
53 min
view live example https //userfirst factory webflow\ io/360pulse/dashboard overview the pulsecheck dashboard provides a comprehensive view of all metrics and feedback related to a specific pulsecheck this page allows users to analyze customer sentiment, track key performance indicators, and identify trends across multiple dimensions page title pulsecheck {pulsecheck name} | 360pulse page structure page html this is the html structure of the age excluding the tiles pulsechecks / {pulsecheck name} {pulsecheck name} pulsecheck {selected pulsecheck name} {pulsecheck name} {selected pulsecheck instance} current {pulsecheck instance name e g february 2025} powered by user first privacy terms of use header & filtering left side breadcrumbs first segment links back to the docid\ qrqi wxnm1yku lpxqdjs page second segment (not a link) shows the name of the current pulsecheck being viewed page title the name of the pulsecheck being viewed right side pulsecheck selector dropdown selector showing the current pulsecheck name (e g "client happiness") click to expand and select between different pulsechecks in the system changing this dropdown navigates to a completely different pulsecheck dashboard instance filter "current" dropdown allows users to filter data by different instances of the same pulsecheck dropdown options options include all previous instances of the pulsecheck options are named using the month and year (e g "janurary 2025") of a previous pulsecheck instance this filter maintains the same pulsecheck but changes the dataset being viewed selection should remain persistent in current session, but reset at next session session by time gap, not login session remove persistence after 2 hours since last viewing this pulsecheck gear icon (button) the gear icon opens the docid fmgs5ceolgp3cezlrs5e page for this pulsecheck filter icon (button) filter funnel icon opens the docid\ y5xmakxpshdvbnolsolj6 modal the modal allows filtering by custom tags configured by the user selected filter options filter the dataset of the current pulsecheck selection should remain persistent in current session, but reset at next session session by time gap, not login session remove persistence after 2 hours since last viewing this pulsecheck remove filter icon (button) remove filter icon is displayed conditionally when a filter is applied clicking the remove filter icon removes all applied filters (from the filter modal) functionality pulsecheck selector completely changes the dashboard context to a different pulsecheck instance filter maintains the same pulsecheck but changes the specific instance/timeframe settings applies specifically to the configuration of the current pulsecheck filter modal provides custom tag based filtering capabilities for advanced data analysis dashboard tiles tiles order metric tiles the metrics tiles go at the top above the results table pulse net promoter score likely to recommend response rate sentiment by area feedback advocacy results table the results table comes next after the metric tiles segment list tiles segment list tiles (top 5) come after the results table most happy most improved new advocates most at rick most declined lost advocates pulse tile details displays overall pulse score (0 100 scale) shows trend indicator (up/down arrow) includes historical line graph showing performance over time primary health indicator for the pulsecheck aggregates feedback from multiple sources data pulse score of pulsecheck instances pulsecheck being viewed + up to 11 preceeding pulsechecks (if they exist) it's important we set the starting point to be the pulsecheck being viewed not the active so it updates appropriately when the user is viewing a different pulsecheck instance tile html pulse {pulse score of selected pulsecheck} tile specific js requires apexcharts js \<! start sparkline area chart for pulse tile > \<script> // array of scores for each previous period (max 12 data previous), if no previous pulsechecks include 1 previous at 0 with label "no previous pulsechecks" const scoredata = \[84, 67, 77, 79, 72, 76, 74, 80, 85, 81]; // array of name of each previous pulsecheck const pulsechecktitles = \[ "june", "july 2024", "august 2024", "september 2024", "october 2024", "november 2024", "december 2024", "janurary 2025", "feburary 2025", "current" ]; // determine the dynamic color based on the latest two entries const latest = scoredata\[scoredata length 1]; const secondlast = scoredata\[scoredata length 2]; let seriescolor; if (latest >= secondlast) { seriescolor = "#34a853"; // green } else { const droppercentage = ((secondlast latest) / secondlast) 100; seriescolor = droppercentage < 3 ? "#ffb300" "#fa4d56"; } // apexcharts configuration const options = { series \[ { name 'pulse score', data scoredata } ], chart { type 'area', height '100%', sparkline { enabled true } }, colors \[seriescolor], stroke { curve 'straight', width 2 }, fill { type 'gradient', gradient { shade 'dark', shadeintensity 0 5, opacityfrom 0 5, opacityto 0 2, stops \[0, 100] } }, tooltip { marker { show false }, x { formatter (val, opts) => pulsechecktitles\[opts datapointindex] || `pulsecheck ${opts datapointindex + 1}` }, y { formatter val => math round(val) } }, datalabels { enabled false } }; const chart = new apexcharts(document queryselector('#pulsescoresparkline'), options); chart render(); \</script> \<! end sparkline area chart for pulse score > drilldown the chart icon in the tiles header links to net promoter score® tile details displays nps score ( 100 to 100 scale) (be aware that displayed score is actual nps score, while the arc is based on percentage nps score of 0 is center this is intentional) semi circular gauge visualization that dynamically changes color based on score legend at bottom showing what the score means, and a caret indicating where their current nps is data nps score of selected pulsecheck instance uses the currently selected instance so it updates when people change the instance dropdown nps score of the pulsecheck instance preceeding the selected pulsecheck data implementation data is added by filling in the attributes on the \<div> with class dashboard gauge change the values for these data chart value current="{nps score of selected pulsecheck instance}" data chart value previous="{nps score of preceeding instance of pulsecheck}" do not change the value for these data chart type="gauge" data chart min=" 100" data chart max="100" data add caret="true" tile html net promoter score® needs improvement( 100 0) good(0 30) great(30 70) excellent(70 100) tile specific js drilldown the chart icon in the tiles header links to likely to recommend tile details displays percentage of respondents likely to recommend circular gauge visualization with trend indicator nps breakdown into color coded spectrum for context detractors % red passives % amber promoters % green data gets the nps breakdown from the selected pulsecheck instance, and the instance preceding it # promoters # passives # detractors calculate for selected and previous pulsecheck % promoters (promoters / (promoters + passives + detractors)) 100 % passives (passives / (promoters + passives + detractors)) 100 % detractors (detractors / (promoters + passives + detractors)) 100 uses the currently selected instance so it updates when people change the instance dropdown tile html likely to recommend tile specific js response rate tile details shows survey completion percentage displays trend indicator represents percentage of invited participants who completed the survey data gets the survey completion % and trend code from the selected pulsecheck instance, and the completion % from the preceeding pulsecheck data implementation update the text in \<div id="response rate percent"> change the style="display none;" to "display flex;" on the div with the icon class tile html response rate {response percent (e g 24%)} tile specific js none sentiment by area tile details displays horizontal bar charts for each pulsecheck question each area shows a numerical average score from all respondents color coded sections represent distribution of responses red negative responses yellow neutral responses green positive responses arrows indicate improving/declining trends compared to previous period data gets the scoring break for each question, for the selected pulsecheck instance # positive # neutral # negative score (which is a number 0 100) trend (up,dn,nc) uses the currently selected instance so it updates when people change the instance dropdown data implementation add a div with class dashboard stacked horizontal bar , for each question and add the following attributes data stacked horizontal label="{question area name (e g "helpdesk"}" data stacked horizontal 1 data="{# negative}" data stacked horizontal 2 data="{# neutral}" data stacked horizontal 3 data="{# positive}" data stacked horizontal pulse="{score}" data stacked horizontal trend="{trend code (e g "up")}" data stacked horizontal 1 url="{link to list report filtered by segment}" data stacked horizontal 2 url="{link to list report filtered by segment}" data stacked horizontal 3 url="{link to list report filtered by segment}" tile html sentiment by area tile specific js feedback tile details summarizes comment metrics total comments overall number of text comments unread comments not yet reviewed positive comments classified as positive sentiment negative comments classified as negative sentiment shows numerical values for each metric data gets the comment stats from the selected pulsecheck instance # positive comments # negative comments gets the number of unread comments related to this instance from the pulsecheck comments table calculate total comments (positive comments + negative comments) uses the currently selected instance so it updates when people change the instance dropdown tile html feedback {# total comments} total comments {# unread comments}} unread {# positive comments} positive {# negative comments} negative tile specific js none advocacy tile details displays metrics related to customer advocacy testimonials number of testimonials provided by respondents review link clicks number of times respondents clicked external review links data gets the testimonial and review link click stats from the selected pulsecheck instance # positive comments # negative comments tile html advocacy {# testimonials} testimonials {# review link clicks} review link clicks tile specific js none pulsecheck results tile (table) details table showing response by respondent across each question/area color coded dots indicate sentiment levels green strong positive sentiment yellow neutral or mixed sentiment red negative sentiment requiring attention variable shades represent nuanced sentiment scores second to last column shows nps score right column shows overall pulse score with trend indicators pagination controls at bottom (default to 30 per page) data gets the questions stats from the selected pulsecheck instance group by tab (if enabled) aggregate results and display as a group get individual results for anyone not belonging to the tag this pulsecheck is aggregated by for example if tag is "client" then all users with "client" "abc corp" would be grouped together and shown as one row if not aggregated get all individual responses for this pulsecheck instance for each results get name (individual or group name) for each question score for individuals ai sentiment if available overrides score nps rating for individuals we store nps rating as you can't score a single response this is their raw answer (0 10) to use on this chart use the following conversion to calculate the nps score 0 6 = 0 7 8 = 50 9 10 = 100 for groups score is calculated already and stored in the nps score field pulse the pulse of the selected pulsecheck instance previous pulse the pulse of the previous pulsecheck instance data aggregation (group by tag) in many cases, our customers need results aggregated at the group level rather than for each individual respondent for example, they may send surveys to multiple people within the same company but prefer to see a single aggregate score for the company instead of individual responses we accomplish this with flexibility by using tags this feature can be enabled in docid fmgs5ceolgp3cezlrs5e when enabled, the system calculates the average scores for all individuals within each group and displays the aggregated results in a single row per group rather than separate entries for each respondent this provides a clearer, high level view of trends across organizations, departments, or other groupings if an individual is not part of a group or does not match the grouping criteria used for aggregation, their results will be displayed separately as an individual entry this ensures that all responses are accounted for, whether grouped or standalone data implementation header row for each question column, in the corresponding th, there will be a div with pulsecheck table heading set the text to be the name of the question / area (e g "helpdesk") add the attribute data tippy content="{full question}" create a row in the table for each respondent (or group) first column respondent or group name n columns 1 column per question inside each table cell, there is a div with class pulsecheck dot on this div add the attribute data pulse score="{individual or group score for this question}" nps column inside the table cell, there is a div with class pulsecheck dot on this div add the attribute data pulse score="{nps score}" pulse column inside the table cell, there is a div with class pulsecheck happiness score badge pulse check score use the pulse score from individuals response (current and previous) if aggregation is on, calculate the averages for selected and previous pulse scores for the group to fill into data pulse score and data pulse score past on this div add the attributes data pulse score="{pulse of selected pulsecheck}" data pulse score past="{pulse of previous pulsecheck}" tile html pulsecheck results respondent {question name / area} recommendation status {respondnent name (individual or group)} pulse 0 items per page 25 25 50 75 100 1–10 of 103 items {current page} {page number} of {# pages} pages tile specific js customer segment list tiles (below table) each of this type of type users the same base html and js structure, only the respodents in the list and the full list links change dashboard card list tile each tile in this segment uses the same common html and js, only the respodents in the list and the full list links change dashboard card list tile html most happy {respondent name} {respondent pulse} dashboard card list item js \<! start dashboard card list item trend arrows > \<script> // dashboard card list item trend script document addeventlistener("domcontentloaded", function() { // find all dashboard card list items const dashboarditems = document queryselectorall(' dashboard card list item'); dashboarditems foreach(item => { // check if the item has both data pulse and data pulse previous attributes const currentscore = item getattribute('data pulse'); const previousscore = item getattribute('data pulse previous'); if (currentscore && previousscore) { // parse scores as integers const current = parseint(currentscore, 10); const previous = parseint(previousscore, 10); if (isnan(current) || isnan(previous)) return; // determine trend let trend = "nc"; if (current > previous) { trend = "up"; } else if (current < previous) { trend = "dn"; } // find the icon element within this dashboard item const iconelement = item queryselector(' icon'); if (!iconelement) return; // find the score element within this dashboard item const scoreelement = item queryselector(' dashboard card list item score'); if (scoreelement) { // update the score element with the current pulse value scoreelement textcontent = current; } // create svg based on trend let svgmarkup = ''; if (trend === 'up') { svgmarkup = ` \<svg xmlns="http //www w3 org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" stroke="var( 360pulse trend up, #4caf50)" stroke width="2" stroke linecap="round" stroke linejoin="round"> \<polyline points="23 6 13 5 15 5 8 5 10 5 1 18">\</polyline> \<polyline points="17 6 23 6 23 12">\</polyline> \</svg>`; } else if (trend === 'dn') { svgmarkup = ` \<svg xmlns="http //www w3 org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" stroke="var( 360pulse trend down, #f44336)" stroke width="2" stroke linecap="round" stroke linejoin="round"> \<polyline points="23 18 13 5 8 5 8 5 13 5 1 6">\</polyline> \<polyline points="17 18 23 18 23 12">\</polyline> \</svg>`; } else if (trend === 'nc') { svgmarkup = ` \<svg xmlns="http //www w3 org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" stroke="var( 360pulse trend no change, #9e9e9e)" stroke width="2" stroke linecap="round" stroke linejoin="round"> \<circle cx="12" cy="12" r="1">\</circle> \<circle cx="19" cy="12" r="1">\</circle> \<circle cx="5" cy="12" r="1">\</circle> \</svg>`; } // update the icon element with the new svg if (svgmarkup) { iconelement innerhtml = svgmarkup; } // add tooltip data attribute for tippy hover information const trendtext = trend === "up" ? "trending up" trend === "dn" ? "trending down" "no change"; item setattribute("data tippy content", `${trendtext}\<br>previous ${previous}`); // add visual data attribute that can be used for additional styling item setattribute("data pulse trend", trend); } }); }); \</script> most happy tile details lists 5 respondents (individuals or groups) with highest overall pulse scores data list of top 5 generated during post processing id id="most happy" most improved tile details lists respondents with greatest increase in pulse score shows numerical ratings with positive change indicators ordered by magnitude of improvement data list of top 5 generated during post processing id id="most improved" new advocates tile details lists respondents who shifted from a non promoter to a promoter data list of top 5 generated during post processing id id="new advocates" most at risk tile details lists respondents with lowest overall pulse scores data list of top 5 generated during post processing id id="most risk" most declined tile details lists respondents with greatest decrease in sentiment scores ordered by magnitude of decline data list of top 5 generated during post processing id id="most declined" lost advocates tile details lists respondents who shifted from promoter to non promoter data list of top 5 generated during post processing id id="lost advocates"