From d3f4a81a89d652f9852d834e29838fca4c135ff6 Mon Sep 17 00:00:00 2001 From: meruff Date: Sun, 21 Aug 2022 15:44:59 -0700 Subject: [PATCH 1/4] Add pagination buttons. Working on query options for page offset and pagination. --- README.md | 2 +- .../TrailheadLeaderboardAuraController.cls | 44 +- ...TrailheadLeaderboardAuraControllerTest.cls | 8 +- .../leaderboardPagination.css | 1 + .../leaderboardPagination.html | 15 + .../leaderboardPagination.js | 11 + .../leaderboardPagination.js-meta.xml | 7 + .../leaderboardProfileTableRow.js | 1 + .../leaderboardTable/leaderboardTable.html | 516 ++++++++---------- .../lwc/leaderboardTable/leaderboardTable.js | 14 +- .../trailheadLeaderboard.html | 16 +- .../trailheadLeaderboard.js | 56 +- manifest/package.xml | 1 + 13 files changed, 382 insertions(+), 310 deletions(-) create mode 100644 force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.css create mode 100644 force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.html create mode 100644 force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js create mode 100644 force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js-meta.xml diff --git a/README.md b/README.md index f9f8b82..7be2a14 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ finished. - ~~Convert to Lightning Web Components ⚡~~ - ~~Convert to Salesforce DX Project~~ - ~~Add a custom Trailhead API~~ -- Dark mode? 😎 +- ~~Dark mode~~ - Pagination / loading more. - Handle deactivating Trailblazers who go private / 404. - Remove `Badge__c`. diff --git a/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls b/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls index 3a67df5..5a49a1f 100644 --- a/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls +++ b/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls @@ -9,16 +9,14 @@ public without sharing class TrailheadLeaderboardAuraController { /** * @description Queries for Trailblazer__c records to display on the page. * - * @param fieldToSortBy the API Name of the field used to sort, defaults to Points__c. - * @param descending whether or not to sort by DESC. + * @param options TrailheadLeaderboardAuraController.TrailblazerQueryConfig record of query options to use. * * @return a List of Trailblazer__c records. + * + * @see TrailheadLeaderboardAuraController.TrailblazerQueryConfig */ @AuraEnabled(Cacheable=true) - public static List populateTrailblazers( - String fieldToSortBy, - Boolean descending - ) { + public static List populateTrailblazers(TrailblazerQueryConfig options) { String queryString = '' + 'SELECT Id, Name, Badges__c, Points__c, Trailblazer_Since__c, Trails__c, Profile_Handle__c, Profile_Id__c, ' + 'Profile_Link__c, Rank__c, Profile_Photo__c, Job_Role__c, Job_Title__c, Company_Institution__c, ' + @@ -27,23 +25,33 @@ public without sharing class TrailheadLeaderboardAuraController { 'WHERE Points__c != NULL ' + 'AND Rank__c != NULL'; - if (String.isBlank(fieldToSortBy)) { + if (String.isBlank(options.sortBy)) { queryString += ' ORDER BY Points__c DESC'; } else { - queryString += ' ORDER BY ' + fieldToSortBy; + queryString += ' ORDER BY ' + options.sortBy; - if (descending == null || descending) { + if (options.descending == null || options.descending) { queryString += ' DESC'; } else { queryString += ' ASC'; } } - return Database.query(queryString); + if (options.pageSize != null) { + queryString += ' LIMIT ' + options.pageSize; + } + + if (options.offset != null) { + queryString += ' OFFSET ' + options.offset; + } + + System.debug(LoggingLevel.DEBUG, 'merf ' + queryString); + + return Database.query(String.escapeSingleQuotes(queryString)); } /** - * @description Creates and upserts a new Trailblazer__c record by calling out to the Trailhead API and + * @description Create and upsert a new Trailblazer__c record by calling out to the Trailhead API and * parsing the response data. * * @param userId the user handle to use when calling out to Trailhead. @@ -224,4 +232,18 @@ public without sharing class TrailheadLeaderboardAuraController { return null; } } + + public class TrailblazerQueryConfig { + @AuraEnabled + public String sortBy { get; set; } + + @AuraEnabled + public Boolean descending { get; set; } + + @AuraEnabled + public Integer pageSize { get; set; } + + @AuraEnabled + public Integer offset { get; set; } + } } \ No newline at end of file diff --git a/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls b/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls index 3357992..2cd5ad8 100644 --- a/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls +++ b/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls @@ -35,7 +35,7 @@ private class TrailheadLeaderboardAuraControllerTest { // Act Test.startTest(); List trailblazers = - TrailheadLeaderboardAuraController.populateTrailblazers('', null); + TrailheadLeaderboardAuraController.populateTrailblazers('', null, null, null); Test.stopTest(); // Assert @@ -52,7 +52,7 @@ private class TrailheadLeaderboardAuraControllerTest { // Act Test.startTest(); List trailblazers = - TrailheadLeaderboardAuraController.populateTrailblazers('Superbadges__c', false); + TrailheadLeaderboardAuraController.populateTrailblazers('Superbadges__c', false, null, null); Test.stopTest(); // Assert @@ -88,7 +88,7 @@ private class TrailheadLeaderboardAuraControllerTest { System.assertEquals('success', resultString); System.assertEquals( 2, - TrailheadLeaderboardAuraController.populateTrailblazers('', null).size(), + TrailheadLeaderboardAuraController.populateTrailblazers('', null, null, null).size(), 'Two Trailblazers should exist now.' ); } @@ -117,7 +117,7 @@ private class TrailheadLeaderboardAuraControllerTest { 'Test Trailblazer should not have been created.'); System.assertNotEquals('success', resultString); System.assertEquals(2, - TrailheadLeaderboardAuraController.populateTrailblazers('', null).size(), + TrailheadLeaderboardAuraController.populateTrailblazers('', null, null, null).size(), 'Only the two Trailblazers should exist, \'someId\' should not have been created.' ); } diff --git a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.css b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.css new file mode 100644 index 0000000..44c96c9 --- /dev/null +++ b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.css @@ -0,0 +1 @@ +@import "c/leaderboardStyles"; \ No newline at end of file diff --git a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.html b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.html new file mode 100644 index 0000000..03afdf9 --- /dev/null +++ b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.html @@ -0,0 +1,15 @@ + diff --git a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js new file mode 100644 index 0000000..5d6658b --- /dev/null +++ b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js @@ -0,0 +1,11 @@ +import { LightningElement } from "lwc"; + +export default class LeaderboardPagination extends LightningElement { + handlePrevious() { + this.dispatchEvent(new CustomEvent("previous")); + } + + handleNext() { + this.dispatchEvent(new CustomEvent("next")); + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js-meta.xml b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js-meta.xml new file mode 100644 index 0000000..9277c5d --- /dev/null +++ b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js-meta.xml @@ -0,0 +1,7 @@ + + + 54.0 + Used to paginate Trailblazers on the leaderboard. + false + Leaderboard Pagination + diff --git a/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.js b/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.js index 8729d91..d3701fa 100644 --- a/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.js +++ b/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.js @@ -6,6 +6,7 @@ import LeaderboardProfileHelper from "c/leaderboardProfileHelper"; export default class LeaderboardProfileTableRow extends LightningElement { @api trailblazer; + @api queryOffset = 0; @api get index() { diff --git a/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html b/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html index 8f5f4dc..ea35d8a 100644 --- a/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html +++ b/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html @@ -1,304 +1,262 @@ diff --git a/force-app/main/default/lwc/leaderboardTable/leaderboardTable.js b/force-app/main/default/lwc/leaderboardTable/leaderboardTable.js index 0247d94..5a78bcc 100644 --- a/force-app/main/default/lwc/leaderboardTable/leaderboardTable.js +++ b/force-app/main/default/lwc/leaderboardTable/leaderboardTable.js @@ -12,7 +12,7 @@ export default class LeaderboardTable extends LightningElement { get trailblazerCountString() { return this.trailblazers && this.trailblazers.length > 0 - ? this.trailblazers.length + " Trailblazers" + ? `${this.trailblazers.length} Trailblazers` : "All Trailblazers"; } @@ -21,7 +21,7 @@ export default class LeaderboardTable extends LightningElement { } get githubLogoUrl() { - return LEADERBOARD_SOURCE + "/trailheadLeaderboard/github.svg"; + return `${LEADERBOARD_SOURCE}/trailheadLeaderboard/github.svg`; } showProfileModal(event) { @@ -42,7 +42,7 @@ export default class LeaderboardTable extends LightningElement { this.isTrailblazerModalOpen = false; } - sort(event) { + handleSort(event) { if (this.fieldToSortBy !== event.target.dataset.field) { this.fieldToSortBy = event.target.dataset.field; this.descending = true; @@ -60,6 +60,14 @@ export default class LeaderboardTable extends LightningElement { ); } + handlePrevious() { + this.dispatchEvent(new CustomEvent("previous")); + } + + handleNext() { + this.dispatchEvent(new CustomEvent("next")); + } + fireRefresh() { this.dispatchEvent(new CustomEvent("refreshtable")); } diff --git a/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.html b/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.html index aca47fb..2638e20 100644 --- a/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.html +++ b/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.html @@ -1,6 +1,12 @@ \ No newline at end of file +
+ + +
+ diff --git a/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js b/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js index 74df775..2f810bf 100644 --- a/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js +++ b/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js @@ -1,21 +1,63 @@ -import { LightningElement, track, wire } from "lwc"; +import { LightningElement, wire } from "lwc"; import populateTrailblazers from "@salesforce/apex/TrailheadLeaderboardAuraController.populateTrailblazers"; import { refreshApex } from "@salesforce/apex"; +const DEFAULT_PAGE_SIZE = 10; +const DEFAULT_PAGE_NUMBER = 1; + export default class TrailheadLeaderboard extends LightningElement { - @track fieldToSortBy = "Points__c"; - @track descending = true; + sortBy = "Points__c"; + descending = true; + pageSize = DEFAULT_PAGE_SIZE; + offset = null; @wire(populateTrailblazers, { - fieldToSortBy: "$fieldToSortBy", - descending: "$descending" + options: "$queryOptions" }) trailblazers; + get pageNumber() { + if (!this._pageNumber) { + return DEFAULT_PAGE_NUMBER; + } + + return this._pageNumber; + } + + set pageNumber(value) { + this._pageNumber = value; + this.offset = + this._pageNumber > 1 ? --this._pageNumber * this.pageSize : null; + } + + get queryOptions() { + return { + sortBy: this.sortBy, + descending: this.descending, + pageSize: this.pageSize, + offset: this.offset + }; + } + handleSort(event) { - this.fieldToSortBy = event.detail.fieldToSortBy; + this.sortBy = event.detail.fieldToSortBy; this.descending = event.detail.descending; - this.refresh(); + } + + handlePrevious() { + console.log("prev"); + this.pageNumber = this.pageNumber !== 1 ? this.pageNumber-- : 1; + } + + handleNext() { + console.log("next"); + // TODO: Some logic here to determine not going past max pages. + this.pageNumber++; + } + + handleSetPageSize(event) { + console.log(event.detail); + this.pageSize = event.detail; } refresh() { diff --git a/manifest/package.xml b/manifest/package.xml index b6d6c26..f0f026b 100644 --- a/manifest/package.xml +++ b/manifest/package.xml @@ -63,6 +63,7 @@ leaderboardTable trailheadLeaderboard leaderboardStyles + leaderboardPagination LightningComponentBundle From ba343f83942df07627ad6ff3b57238255e692d17 Mon Sep 17 00:00:00 2001 From: meruff Date: Wed, 31 Aug 2022 18:43:10 -0700 Subject: [PATCH 2/4] Got pagination working on desktop. Working on Mobile - Clean up some code. - Convert to Railway app, drop Heroku. --- .../default/classes/CertificationData.cls | 14 +- .../classes/GetTrailblazerInfoAsync.cls | 60 ++-- .../classes/GetTrailblazerInfoAsyncTest.cls | 187 +++++++------ .../default/classes/PopulateTrailblazers.cls | 5 +- .../classes/PopulateTrailblazersTest.cls | 67 +++-- .../main/default/classes/ProfileData.cls | 2 +- .../default/classes/TrailheadCalloutMock.cls | 60 ++-- .../default/classes/TrailheadGraphQlData.cls | 2 +- .../main/default/classes/TrailheadHelper.cls | 12 +- .../TrailheadLeaderboardAuraController.cls | 97 ++++--- ...TrailheadLeaderboardAuraControllerTest.cls | 95 +++++-- .../lwc/alertMessage/alertMessage.html | 64 ++--- .../leaderboardBadges/leaderboardBadges.html | 159 +++++------ .../leaderboardCertification.html | 83 +++--- .../leaderboardCertifications.html | 88 +++--- .../leaderboardCertifications.js | 2 +- .../leaderboardHeader/leaderboardHeader.html | 10 +- .../leaderboardNewTrailblazerModal.html | 165 ++++++----- .../leaderboardPagination.css | 2 +- .../leaderboardPagination.html | 39 ++- .../leaderboardPagination.js | 52 +++- .../leaderboardProfileCard.html | 258 +++++++++--------- .../leaderboardProfileModal.html | 144 +++++----- .../leaderboardProfileTableRow.html | 156 ++++++----- .../leaderboardProfileTableRow.js | 21 +- .../lwc/leaderboardRank/leaderboardRank.html | 4 +- .../leaderboardRankBadge.html | 11 +- .../leaderboardRankBadge.js | 11 +- .../leaderboardSkills/leaderboardSkills.html | 48 ++-- .../leaderboardSortDir.html | 22 +- .../leaderboardSortDir/leaderboardSortDir.js | 6 +- .../leaderboardTable/leaderboardTable.html | 85 +++--- .../lwc/leaderboardTable/leaderboardTable.js | 35 ++- .../trailheadLeaderboard.html | 5 + .../trailheadLeaderboard.js | 74 +++-- .../default/pages/trailheadLeaderboard.page | 5 - ...ilhead_Leaderboard_API.remoteSite-meta.xml | 2 +- package.json | 2 +- 38 files changed, 1165 insertions(+), 989 deletions(-) diff --git a/force-app/main/default/classes/CertificationData.cls b/force-app/main/default/classes/CertificationData.cls index e5acfa8..998e858 100644 --- a/force-app/main/default/classes/CertificationData.cls +++ b/force-app/main/default/classes/CertificationData.cls @@ -1,12 +1,12 @@ /** -* @author meruff -* @date 3/18/20 -* -* A class to deserialize Trailhead Certification data from the API into. -*/ + * @author meruff + * @date 3/18/20 + * + * A class to deserialize Trailhead Certification data from the API into. + */ public class CertificationData { public String error { get; set; } - + @AuraEnabled public List certificationsList { get; set; } @@ -32,4 +32,4 @@ public class CertificationData { @AuraEnabled public String certificationImageUrl { get; set; } } -} \ No newline at end of file +} diff --git a/force-app/main/default/classes/GetTrailblazerInfoAsync.cls b/force-app/main/default/classes/GetTrailblazerInfoAsync.cls index 40457bc..857fe61 100644 --- a/force-app/main/default/classes/GetTrailblazerInfoAsync.cls +++ b/force-app/main/default/classes/GetTrailblazerInfoAsync.cls @@ -22,10 +22,22 @@ public class GetTrailblazerInfoAsync implements Queueable, Database.AllowsCallou } Trailblazer__c trailblazer = trailblazers[0]; - getProfileData(trailblazer, TrailheadHelper.buildCalloutURL(trailblazer, TrailheadHelper.PROFILE_PATH)); - getRankData(trailblazer, TrailheadHelper.buildCalloutURL(trailblazer, TrailheadHelper.RANK_PATH)); - getSuperbadgeData(trailblazer, TrailheadHelper.buildCalloutURL(trailblazer, TrailheadHelper.SUPERBADGES_PATH)); - getCertificationData(trailblazer, TrailheadHelper.buildCalloutURL(trailblazer, TrailheadHelper.CERTIFICATIONS_PATH)); + getProfileData( + trailblazer, + TrailheadHelper.buildCalloutURL(trailblazer, TrailheadHelper.PROFILE_PATH) + ); + getRankData( + trailblazer, + TrailheadHelper.buildCalloutURL(trailblazer, TrailheadHelper.RANK_PATH) + ); + getSuperbadgeData( + trailblazer, + TrailheadHelper.buildCalloutURL(trailblazer, TrailheadHelper.SUPERBADGES_PATH) + ); + getCertificationData( + trailblazer, + TrailheadHelper.buildCalloutURL(trailblazer, TrailheadHelper.CERTIFICATIONS_PATH) + ); if (!String.isBlank(trailblazer.Profile_Handle__c)) { upsert trailblazer Profile_Handle__c; @@ -54,8 +66,10 @@ public class GetTrailblazerInfoAsync implements Queueable, Database.AllowsCallou * @return a string representing a successful callout. */ public static String getProfileData(Trailblazer__c trailblazer, String resBody) { - if (resBody.contains(TrailheadHelper.HEROKU_ERROR) || String.isBlank(resBody)) { - return TrailheadHelper.buildErrorAsJSON('Application Error, please try again. API may be down.'); + if (resBody.contains(TrailheadHelper.API_ERROR) || String.isBlank(resBody)) { + return TrailheadHelper.buildErrorAsJSON( + 'Application Error, please try again. API may be down.' + ); } ProfileData data = (ProfileData) JSON.deserialize( @@ -77,9 +91,11 @@ public class GetTrailblazerInfoAsync implements Queueable, Database.AllowsCallou trailblazer.Job_Role__c = data.profileUser.TBID_Role; if (!String.isBlank(data.profileUser.TrailblazerId)) { - trailblazer.Profile_Link__c = TrailheadHelper.TRAILHEAD_ME + data.profileUser.TrailblazerId; + trailblazer.Profile_Link__c = + TrailheadHelper.TRAILHEAD_ME + data.profileUser.TrailblazerId; } else { - trailblazer.Profile_Link__c = TrailheadHelper.TRAILHEAD_ME_USERID + data.profileUser.Id; + trailblazer.Profile_Link__c = + TrailheadHelper.TRAILHEAD_ME_USERID + data.profileUser.Id; } } @@ -95,14 +111,14 @@ public class GetTrailblazerInfoAsync implements Queueable, Database.AllowsCallou * @return a string representing a successful callout. */ public static String getRankData(Trailblazer__c trailblazer, String resBody) { - if (resBody.contains(TrailheadHelper.HEROKU_ERROR) || String.isBlank(resBody)) { - return TrailheadHelper.buildErrorAsJSON('Application Error, please try again. API may be down.'); + if (resBody.contains(TrailheadHelper.API_ERROR) || String.isBlank(resBody)) { + return TrailheadHelper.buildErrorAsJSON( + 'Application Error, please try again. API may be down.' + ); } TrailheadGraphQlData data = (TrailheadGraphQlData) JSON.deserialize( - resBody - .replaceAll('__c', '') - .replaceAll('__', ''), + resBody.replaceAll('__c', '').replaceAll('__', ''), TrailheadGraphQlData.class ); @@ -130,14 +146,14 @@ public class GetTrailblazerInfoAsync implements Queueable, Database.AllowsCallou * @return a string representing a successful callout. */ public static String getSuperbadgeData(Trailblazer__c trailblazer, String resBody) { - if (resBody.contains(TrailheadHelper.HEROKU_ERROR) || String.isBlank(resBody)) { - return TrailheadHelper.buildErrorAsJSON('Application Error, please try again. API may be down.'); + if (resBody.contains(TrailheadHelper.API_ERROR) || String.isBlank(resBody)) { + return TrailheadHelper.buildErrorAsJSON( + 'Application Error, please try again. API may be down.' + ); } TrailheadGraphQlData data = (TrailheadGraphQlData) JSON.deserialize( - resBody - .replaceAll('__c', '') - .replaceAll('__', ''), + resBody.replaceAll('__c', '').replaceAll('__', ''), TrailheadGraphQlData.class ); @@ -169,8 +185,10 @@ public class GetTrailblazerInfoAsync implements Queueable, Database.AllowsCallou * @return a string representing a successful callout. */ public static String getCertificationData(Trailblazer__c trailblazer, String resBody) { - if (resBody.contains(TrailheadHelper.HEROKU_ERROR) || String.isBlank(resBody)) { - return TrailheadHelper.buildErrorAsJSON('Application Error, please try again. API may be down.'); + if (resBody.contains(TrailheadHelper.API_ERROR) || String.isBlank(resBody)) { + return TrailheadHelper.buildErrorAsJSON( + 'Application Error, please try again. API may be down.' + ); } CertificationData data = (CertificationData) JSON.deserialize( @@ -188,4 +206,4 @@ public class GetTrailblazerInfoAsync implements Queueable, Database.AllowsCallou return TrailheadHelper.SUCCESS; } -} \ No newline at end of file +} diff --git a/force-app/main/default/classes/GetTrailblazerInfoAsyncTest.cls b/force-app/main/default/classes/GetTrailblazerInfoAsyncTest.cls index 4dc1d9b..14c1229 100644 --- a/force-app/main/default/classes/GetTrailblazerInfoAsyncTest.cls +++ b/force-app/main/default/classes/GetTrailblazerInfoAsyncTest.cls @@ -9,10 +9,7 @@ private class GetTrailblazerInfoAsyncTest { @TestSetup static void setUpData() { - insert new Trailblazer__c( - Name = 'mat ruff', - Profile_Handle__c = 'matruff' - ); + insert new Trailblazer__c(Name = 'mat ruff', Profile_Handle__c = 'matruff'); } /** @@ -36,32 +33,39 @@ private class GetTrailblazerInfoAsyncTest { System.enqueueJob( new GetTrailblazerInfoAsync( 0, - new List([ - SELECT Profile_Handle__c, - Profile_Id__c - FROM Trailblazer__c - ]) + new List( + [SELECT Profile_Handle__c, Profile_Id__c FROM Trailblazer__c] + ) ) ); Test.stopTest(); // Assert List assertTrailblazers = [ - SELECT Name, - Badges__c, - Trails__c, - Superbadges__c + SELECT Name, Badges__c, Trails__c, Superbadges__c FROM Trailblazer__c ]; - System.assertEquals(1, assertTrailblazers.size(), - 'Should have created 1 Trailblazer during test set up and upserted that singular record.'); - System.assertEquals(168, assertTrailblazers[0].Badges__c, - '168 badges should have been created from the profile counts data.'); - System.assertEquals(1, assertTrailblazers[0].Superbadges__c, - 'One superbadge should have been created.'); - System.assertEquals(21, assertTrailblazers[0].Trails__c, - 'Trails__c should have been upserted to 21'); + System.assertEquals( + 1, + assertTrailblazers.size(), + 'Should have created 1 Trailblazer during test set up and upserted that singular record.' + ); + System.assertEquals( + 168, + assertTrailblazers[0].Badges__c, + '168 badges should have been created from the profile counts data.' + ); + System.assertEquals( + 1, + assertTrailblazers[0].Superbadges__c, + 'One superbadge should have been created.' + ); + System.assertEquals( + 21, + assertTrailblazers[0].Trails__c, + 'Trails__c should have been upserted to 21' + ); } /** @@ -80,11 +84,9 @@ private class GetTrailblazerInfoAsyncTest { Test.setMock(HttpCalloutMock.class, mock); - Trailblazer__c testTrailblazer = new List([ - SELECT Profile_Handle__c, - Profile_Id__c - FROM Trailblazer__c - ])[0]; + Trailblazer__c testTrailblazer = new List( + [SELECT Profile_Handle__c, Profile_Id__c FROM Trailblazer__c] + )[0]; testTrailblazer.Superbadges__c = 3; update testTrailblazer; // Set existing Trailblazer superbadges to 3. @@ -104,8 +106,11 @@ private class GetTrailblazerInfoAsyncTest { WHERE Id = :testTrailblazer.Id ]; - System.assertEquals(3, assertTrailblazer.Superbadges__c, - 'Superbadges should not have been updated from a failed server callout.'); + System.assertEquals( + 3, + assertTrailblazer.Superbadges__c, + 'Superbadges should not have been updated from a failed server callout.' + ); } /** @@ -124,11 +129,9 @@ private class GetTrailblazerInfoAsyncTest { Test.setMock(HttpCalloutMock.class, mock); - Trailblazer__c testTrailblazer = new List([ - SELECT Profile_Handle__c, - Profile_Id__c - FROM Trailblazer__c - ])[0]; + Trailblazer__c testTrailblazer = new List( + [SELECT Profile_Handle__c, Profile_Id__c FROM Trailblazer__c] + )[0]; testTrailblazer.Certifications__c = 5; update testTrailblazer; // Set existing Trailblazer certifications to 5. @@ -148,12 +151,15 @@ private class GetTrailblazerInfoAsyncTest { WHERE Id = :testTrailblazer.Id ]; - System.assertEquals(5, assertTrailblazer.Certifications__c, - 'Certifications should not have been updated from a failed server callout.'); + System.assertEquals( + 5, + assertTrailblazer.Certifications__c, + 'Certifications should not have been updated from a failed server callout.' + ); } /** - * @description Tests an error with the Heroku application being down. + * @description Tests an error with the remote API application being down. */ @IsTest static void testGetTrailblazerInfoApplicationError() { @@ -172,35 +178,45 @@ private class GetTrailblazerInfoAsyncTest { Test.startTest(); System.enqueueJob( new GetTrailblazerInfoAsync( - 0, new List([ - SELECT Profile_Handle__c, - Profile_Id__c - FROM Trailblazer__c - ]) + 0, + new List( + [SELECT Profile_Handle__c, Profile_Id__c FROM Trailblazer__c] + ) ) ); Test.stopTest(); // Assert List assertTrailblazers = [ - SELECT Name, - Badges__c, - Trails__c, - Superbadges__c, - Certifications__c + SELECT Name, Badges__c, Trails__c, Superbadges__c, Certifications__c FROM Trailblazer__c ]; - System.assertEquals(1, assertTrailblazers.size(), - 'Should have created 1 Trailblazer during test set up and upserted that singular record.'); - System.assertEquals(0, assertTrailblazers[0].Badges__c, - '0 badges should have been created from the profile counts data.'); - System.assertEquals(0, assertTrailblazers[0].Superbadges__c, - '0 superbadges should have been created.'); - System.assertEquals(0, assertTrailblazers[0].Certifications__c, - '0 certifications should have been created.'); - System.assertEquals(0, assertTrailblazers[0].Trails__c, - '0 Trails__c should have been created.'); + System.assertEquals( + 1, + assertTrailblazers.size(), + 'Should have created 1 Trailblazer during test set up and upserted that singular record.' + ); + System.assertEquals( + 0, + assertTrailblazers[0].Badges__c, + '0 badges should have been created from the profile counts data.' + ); + System.assertEquals( + 0, + assertTrailblazers[0].Superbadges__c, + '0 superbadges should have been created.' + ); + System.assertEquals( + 0, + assertTrailblazers[0].Certifications__c, + '0 certifications should have been created.' + ); + System.assertEquals( + 0, + assertTrailblazers[0].Trails__c, + '0 Trails__c should have been created.' + ); } @IsTest @@ -220,37 +236,50 @@ private class GetTrailblazerInfoAsyncTest { Test.startTest(); System.enqueueJob( new GetTrailblazerInfoAsync( - 0, new List([ - SELECT Profile_Handle__c, - Profile_Id__c - FROM Trailblazer__c - ]) + 0, + new List( + [SELECT Profile_Handle__c, Profile_Id__c FROM Trailblazer__c] + ) ) ); Test.stopTest(); // Assert List assertTrailblazers = [ - SELECT Name, - Certifications__c, - Company_Institution__c, - Job_Title__c, - Job_Role__c + SELECT Name, Certifications__c, Company_Institution__c, Job_Title__c, Job_Role__c FROM Trailblazer__c ]; // Assert - System.assertEquals(1, assertTrailblazers.size(), - 'Should have created 1 Trailblazer during test set up and upserted that singular record.'); - System.assertEquals('Mat Ruff', assertTrailblazers[0].Name, - 'Name should have been upserted to capitalized \'Mat Ruff\'.'); - System.assertEquals('ABC Co.', assertTrailblazers[0].Company_Institution__c, - 'Name should have been upserted to \'ABC Co.\'.'); - System.assertEquals('Senior Developer', assertTrailblazers[0].Job_Title__c, - 'Name should have been upserted to \'Senior Developer\'.'); - System.assertEquals('Developer', assertTrailblazers[0].Job_Role__c, - 'Name should have been upserted to \'Developer\'.'); - System.assertEquals(1, assertTrailblazers[0].Certifications__c, - 'One certification should have been created.'); + System.assertEquals( + 1, + assertTrailblazers.size(), + 'Should have created 1 Trailblazer during test set up and upserted that singular record.' + ); + System.assertEquals( + 'Mat Ruff', + assertTrailblazers[0].Name, + 'Name should have been upserted to capitalized \'Mat Ruff\'.' + ); + System.assertEquals( + 'ABC Co.', + assertTrailblazers[0].Company_Institution__c, + 'Name should have been upserted to \'ABC Co.\'.' + ); + System.assertEquals( + 'Senior Developer', + assertTrailblazers[0].Job_Title__c, + 'Name should have been upserted to \'Senior Developer\'.' + ); + System.assertEquals( + 'Developer', + assertTrailblazers[0].Job_Role__c, + 'Name should have been upserted to \'Developer\'.' + ); + System.assertEquals( + 1, + assertTrailblazers[0].Certifications__c, + 'One certification should have been created.' + ); } -} \ No newline at end of file +} diff --git a/force-app/main/default/classes/PopulateTrailblazers.cls b/force-app/main/default/classes/PopulateTrailblazers.cls index 5b3a771..ee09d41 100644 --- a/force-app/main/default/classes/PopulateTrailblazers.cls +++ b/force-app/main/default/classes/PopulateTrailblazers.cls @@ -36,5 +36,6 @@ global class PopulateTrailblazers implements Database.Batchable, Databa } } - global void finish(Database.BatchableContext BC) { } -} \ No newline at end of file + global void finish(Database.BatchableContext BC) { + } +} diff --git a/force-app/main/default/classes/PopulateTrailblazersTest.cls b/force-app/main/default/classes/PopulateTrailblazersTest.cls index fa064f2..cadaf2f 100644 --- a/force-app/main/default/classes/PopulateTrailblazersTest.cls +++ b/force-app/main/default/classes/PopulateTrailblazersTest.cls @@ -1,9 +1,9 @@ /** -* @author: meruff -* @date: 2017-07-27 -* -* Unit Tests for PopulateTrailblazers.cls -*/ + * @author: meruff + * @date: 2017-07-27 + * + * Unit Tests for PopulateTrailblazers.cls + */ @IsTest private class PopulateTrailblazersTest { @IsTest @@ -15,17 +15,11 @@ private class PopulateTrailblazersTest { @IsTest static void testExecuteBatchWithScope() { - insert new Trailblazer__c( - Name = 'mat ruff', - Profile_Handle__c = 'matruff' - ); + insert new Trailblazer__c(Name = 'mat ruff', Profile_Handle__c = 'matruff'); Test.startTest(); Database.executeBatch( - new PopulateTrailblazers([ - SELECT Profile_Handle__c, Profile_Id__c - FROM Trailblazer__c - ]) + new PopulateTrailblazers([SELECT Profile_Handle__c, Profile_Id__c FROM Trailblazer__c]) ); Test.stopTest(); } @@ -34,31 +28,46 @@ private class PopulateTrailblazersTest { static void testSchedulePopulation() { // Act Test.startTest(); - String assertJobId = System.schedule('Test Scheduling PopulateTrailblazers', '0 0 23 * * ?', new PopulateTrailblazers()); + String assertJobId = System.schedule( + 'Test Scheduling PopulateTrailblazers', + '0 0 23 * * ?', + new PopulateTrailblazers() + ); Test.stopTest(); // Assert List assertScheduledJobs = [ - SELECT ApexClass.Name - FROM AsyncApexJob + SELECT ApexClass.Name + FROM AsyncApexJob WHERE JobType = 'ScheduledApex' ]; - - System.assertEquals('PopulateTrailblazers', assertScheduledJobs[0].ApexClass.Name, - 'PopulateTrailblazers should be scheduled.'); - System.assertEquals(1, assertScheduledJobs.size(), - 'Only PopulateTrailblazers should be in the queue.'); - + + System.assertEquals( + 'PopulateTrailblazers', + assertScheduledJobs[0].ApexClass.Name, + 'PopulateTrailblazers should be scheduled.' + ); + System.assertEquals( + 1, + assertScheduledJobs.size(), + 'Only PopulateTrailblazers should be in the queue.' + ); List assertBatchJobs = [ - SELECT ApexClass.Name - FROM AsyncApexJob + SELECT ApexClass.Name + FROM AsyncApexJob WHERE JobType = 'BatchApex' ]; - System.assertEquals('PopulateTrailblazers', assertBatchJobs[0].ApexClass.Name, - 'PopulateTrailblazers should be in the batch queue.'); - System.assertEquals(1, assertBatchJobs.size(), - 'Only PopulateTrailblazers should be in the queue.'); + System.assertEquals( + 'PopulateTrailblazers', + assertBatchJobs[0].ApexClass.Name, + 'PopulateTrailblazers should be in the batch queue.' + ); + System.assertEquals( + 1, + assertBatchJobs.size(), + 'Only PopulateTrailblazers should be in the queue.' + ); } -} \ No newline at end of file +} diff --git a/force-app/main/default/classes/ProfileData.cls b/force-app/main/default/classes/ProfileData.cls index 362d690..e062762 100644 --- a/force-app/main/default/classes/ProfileData.cls +++ b/force-app/main/default/classes/ProfileData.cls @@ -19,4 +19,4 @@ public class ProfileData { public String LastName { get; set; } public String Id { get; set; } } -} \ No newline at end of file +} diff --git a/force-app/main/default/classes/TrailheadCalloutMock.cls b/force-app/main/default/classes/TrailheadCalloutMock.cls index 7bc0558..00b5d96 100644 --- a/force-app/main/default/classes/TrailheadCalloutMock.cls +++ b/force-app/main/default/classes/TrailheadCalloutMock.cls @@ -1,10 +1,10 @@ /** -* @description Mock callout class for PopulateTrailblazers.cls + * @description Mock callout class for PopulateTrailblazers.cls * -* @author: meruff + * @author: meruff * -* @date: 2017-07-27 -*/ + * @date: 2017-07-27 + */ @IsTest public class TrailheadCalloutMock implements HttpCalloutMock { // TODO: @@ -25,31 +25,31 @@ public class TrailheadCalloutMock implements HttpCalloutMock { public static String getSuccessfulTrailheadResponse() { return '' + '{' + - '"profileUser": {' + - '"AboutMe": null,' + - '"FirstName": "Mat",' + - '"StateCode": "AZ",' + - '"Title": "Senior Developer",' + - '"Relationship_To_Salesforce__c": "Partner",' + - '"TBID_Role__c": "Developer",' + - '"CompanyName": "ABC Co.",' + - '"TrailblazerId__c": "matruff",' + - '"LastName": "Ruff",' + - '"Id": "0051I000004UgTlQAK"' + - '},' + - '"profilePhotoUrl": "https://trailblazer.me/profilephoto/7291I000000Jm2C/M",' + - '"certificationsList":[' + - '{' + - '"visibleToYouDescription":null,' + - '"title":"Salesforce Certified Administrator",' + - '"description":"Certified Administrators are Salesforce pros who are always looking for ways to help their companies get even more out of the Salesforce Platform through additional features and capabilities.",' + - '"dateExpired":null,' + - '"dateCompleted":"2013-06-13",' + - '"certificationUrl":"https://trailhead.salesforce.com/credentials/administrator",' + - '"certificationStatus":"ACTIVE",' + - '"certificationImageUrl":"https://drm--c.na114.content.force.com/servlet/servlet.ImageServer?id=0153k00000AH6hb&oid=00DF0000000gZsu&lastMod=1571903578000"' + - '}' + - ']' + + '"profileUser": {' + + '"AboutMe": null,' + + '"FirstName": "Mat",' + + '"StateCode": "AZ",' + + '"Title": "Senior Developer",' + + '"Relationship_To_Salesforce__c": "Partner",' + + '"TBID_Role__c": "Developer",' + + '"CompanyName": "ABC Co.",' + + '"TrailblazerId__c": "matruff",' + + '"LastName": "Ruff",' + + '"Id": "0051I000004UgTlQAK"' + + '},' + + '"profilePhotoUrl": "https://trailblazer.me/profilephoto/7291I000000Jm2C/M",' + + '"certificationsList":[' + + '{' + + '"visibleToYouDescription":null,' + + '"title":"Salesforce Certified Administrator",' + + '"description":"Certified Administrators are Salesforce pros who are always looking for ways to help their companies get even more out of the Salesforce Platform through additional features and capabilities.",' + + '"dateExpired":null,' + + '"dateCompleted":"2013-06-13",' + + '"certificationUrl":"https://trailhead.salesforce.com/credentials/administrator",' + + '"certificationStatus":"ACTIVE",' + + '"certificationImageUrl":"https://drm--c.na114.content.force.com/servlet/servlet.ImageServer?id=0153k00000AH6hb&oid=00DF0000000gZsu&lastMod=1571903578000"' + + '}' + + ']' + '}'; } @@ -179,4 +179,4 @@ public class TrailheadCalloutMock implements HttpCalloutMock { public static String getApplicationDownResponseData() { return 'Application error'; } -} \ No newline at end of file +} diff --git a/force-app/main/default/classes/TrailheadGraphQlData.cls b/force-app/main/default/classes/TrailheadGraphQlData.cls index b68dadc..4cc0bbf 100644 --- a/force-app/main/default/classes/TrailheadGraphQlData.cls +++ b/force-app/main/default/classes/TrailheadGraphQlData.cls @@ -109,4 +109,4 @@ public class TrailheadGraphQlData { @AuraEnabled public content content { get; set; } } -} \ No newline at end of file +} diff --git a/force-app/main/default/classes/TrailheadHelper.cls b/force-app/main/default/classes/TrailheadHelper.cls index e494c4d..f2431ca 100644 --- a/force-app/main/default/classes/TrailheadHelper.cls +++ b/force-app/main/default/classes/TrailheadHelper.cls @@ -6,13 +6,13 @@ * @date 7/25/22 */ public class TrailheadHelper { - public static final String GO_TRAILHEAD_API = 'https://go-trailhead-leaderboard-api.herokuapp.com/trailblazer/'; + public static final String GO_TRAILHEAD_API = 'https://go-trailhead-leaderboard-api.up.railway.app/trailblazer/'; public static final String TRAILHEAD_ME = 'https://trailblazer.me/id/'; public static final String TRAILHEAD_ME_USERID = 'https://trailblazer.me/id?cmty=trailhead&uid='; public static final String BADGES_PATH = '/badges'; public static final String CERTIFICATIONS_PATH = '/certifications'; - public static final String HEROKU_ERROR = 'Application error'; + public static final String API_ERROR = 'Application error'; public static final String PROFILE_PATH = '/profile'; public static final String RANK_PATH = '/rank'; public static final String SKILLS_PATH = '/skills'; @@ -30,11 +30,11 @@ public class TrailheadHelper { * @see TrailheadHelper.doCallout */ public static String buildCalloutURL(Trailblazer__c trailblazer, String path) { - return TrailheadHelper.doCallout(TrailheadHelper.GO_TRAILHEAD_API + + return TrailheadHelper.doCallout( + TrailheadHelper.GO_TRAILHEAD_API + (String.isNotBlank(trailblazer.Profile_Handle__c) ? trailblazer.Profile_Handle__c - : trailblazer.Profile_Id__c - ) + + : trailblazer.Profile_Id__c) + path ); } @@ -75,4 +75,4 @@ public class TrailheadHelper { this.error = message; } } -} \ No newline at end of file +} diff --git a/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls b/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls index 5a49a1f..fa8ccea 100644 --- a/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls +++ b/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls @@ -17,10 +17,11 @@ public without sharing class TrailheadLeaderboardAuraController { */ @AuraEnabled(Cacheable=true) public static List populateTrailblazers(TrailblazerQueryConfig options) { - String queryString = '' + + String queryString = + '' + 'SELECT Id, Name, Badges__c, Points__c, Trailblazer_Since__c, Trails__c, Profile_Handle__c, Profile_Id__c, ' + - 'Profile_Link__c, Rank__c, Profile_Photo__c, Job_Role__c, Job_Title__c, Company_Institution__c, ' + - 'Rank_Badge_Link__c, Superbadges__c, Certifications__c, LastModifiedDate ' + + 'Profile_Link__c, Rank__c, Profile_Photo__c, Job_Role__c, Job_Title__c, Company_Institution__c, ' + + 'Rank_Badge_Link__c, Superbadges__c, Certifications__c, LastModifiedDate ' + 'FROM Trailblazer__c ' + 'WHERE Points__c != NULL ' + 'AND Rank__c != NULL'; @@ -45,11 +46,19 @@ public without sharing class TrailheadLeaderboardAuraController { queryString += ' OFFSET ' + options.offset; } - System.debug(LoggingLevel.DEBUG, 'merf ' + queryString); - return Database.query(String.escapeSingleQuotes(queryString)); } + /** + * @description Runs an AggregateResult query for COUNT of all Trailblazer__c records. + * + * @return an Integer representing the count. + */ + @AuraEnabled(Cacheable=true) + public static Integer getTotalTrailblazerCount() { + return (Integer) [SELECT COUNT(Id) FROM Trailblazer__c][0]?.get('expr0'); + } + /** * @description Create and upsert a new Trailblazer__c record by calling out to the Trailhead API and * parsing the response data. @@ -64,39 +73,32 @@ public without sharing class TrailheadLeaderboardAuraController { Profile_Handle__c = userId.replace(' ', '').trim() ); - for (String s : new Set{ - GetTrailblazerInfoAsync.getProfileData( - newTrailblazer, - TrailheadHelper.buildCalloutURL( + for ( + String s : new Set{ + GetTrailblazerInfoAsync.getProfileData( newTrailblazer, - TrailheadHelper.PROFILE_PATH - ) - ), - - GetTrailblazerInfoAsync.getRankData( - newTrailblazer, - TrailheadHelper.buildCalloutURL( + TrailheadHelper.buildCalloutURL(newTrailblazer, TrailheadHelper.PROFILE_PATH) + ), + GetTrailblazerInfoAsync.getRankData( newTrailblazer, - TrailheadHelper.RANK_PATH - ) - ), - - GetTrailblazerInfoAsync.getSuperbadgeData( - newTrailblazer, - TrailheadHelper.buildCalloutURL( + TrailheadHelper.buildCalloutURL(newTrailblazer, TrailheadHelper.RANK_PATH) + ), + GetTrailblazerInfoAsync.getSuperbadgeData( newTrailblazer, - TrailheadHelper.SUPERBADGES_PATH - ) - ), - - GetTrailblazerInfoAsync.getCertificationData( - newTrailblazer, - TrailheadHelper.buildCalloutURL( + TrailheadHelper.buildCalloutURL( + newTrailblazer, + TrailheadHelper.SUPERBADGES_PATH + ) + ), + GetTrailblazerInfoAsync.getCertificationData( newTrailblazer, - TrailheadHelper.CERTIFICATIONS_PATH + TrailheadHelper.buildCalloutURL( + newTrailblazer, + TrailheadHelper.CERTIFICATIONS_PATH + ) ) - ) - }) { + } + ) { if (!s.equals(TrailheadHelper.SUCCESS)) { return s; } @@ -153,15 +155,11 @@ public without sharing class TrailheadLeaderboardAuraController { } TrailheadGraphQlData data = (TrailheadGraphQlData) JSON.deserialize( - resBody - .replaceAll('__c', '') - .replaceAll('__', ''), + resBody.replaceAll('__c', '').replaceAll('__', ''), TrailheadGraphQlData.class ); - if (String.isBlank(data.error) - && data.profile?.earnedAwards != null - ) { + if (String.isBlank(data.error) && data.profile?.earnedAwards != null) { return data.profile.earnedAwards; } else { return null; @@ -178,7 +176,9 @@ public without sharing class TrailheadLeaderboardAuraController { @AuraEnabled public static List getSkillData(String userId) { String resBody = TrailheadHelper.doCallout( - TrailheadHelper.GO_TRAILHEAD_API + userId + TrailheadHelper.SKILLS_PATH + TrailheadHelper.GO_TRAILHEAD_API + + userId + + TrailheadHelper.SKILLS_PATH ); if (resBody.contains('application-error')) { @@ -186,15 +186,11 @@ public without sharing class TrailheadLeaderboardAuraController { } TrailheadGraphQlData data = (TrailheadGraphQlData) JSON.deserialize( - resBody - .replaceAll('__c', '') - .replaceAll('__', ''), + resBody.replaceAll('__c', '').replaceAll('__', ''), TrailheadGraphQlData.class ); - if (String.isBlank(data.error) - && data?.profile?.earnedSkills != null - ) { + if (String.isBlank(data.error) && data?.profile?.earnedSkills != null) { return data?.profile?.earnedSkills; } else { return null; @@ -212,7 +208,8 @@ public without sharing class TrailheadLeaderboardAuraController { public static List getCertificationData(String userId) { String resBody = TrailheadHelper.doCallout( TrailheadHelper.GO_TRAILHEAD_API + - userId + TrailheadHelper.CERTIFICATIONS_PATH + userId + + TrailheadHelper.CERTIFICATIONS_PATH ); if (resBody.contains('application-error')) { @@ -224,9 +221,7 @@ public without sharing class TrailheadLeaderboardAuraController { CertificationData.class ); - if (String.isBlank(data.error) - && data?.certificationsList != null - ) { + if (String.isBlank(data.error) && data?.certificationsList != null) { return data.certificationsList; } else { return null; @@ -246,4 +241,4 @@ public without sharing class TrailheadLeaderboardAuraController { @AuraEnabled public Integer offset { get; set; } } -} \ No newline at end of file +} diff --git a/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls b/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls index 2cd5ad8..6c08fd6 100644 --- a/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls +++ b/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls @@ -34,8 +34,9 @@ private class TrailheadLeaderboardAuraControllerTest { static void testPopulateTrailblazers() { // Act Test.startTest(); - List trailblazers = - TrailheadLeaderboardAuraController.populateTrailblazers('', null, null, null); + List trailblazers = TrailheadLeaderboardAuraController.populateTrailblazers( + new TrailheadLeaderboardAuraController.TrailblazerQueryConfig() + ); Test.stopTest(); // Assert @@ -51,8 +52,11 @@ private class TrailheadLeaderboardAuraControllerTest { static void testPopulateTrailblazersSort() { // Act Test.startTest(); - List trailblazers = - TrailheadLeaderboardAuraController.populateTrailblazers('Superbadges__c', false, null, null); + TrailheadLeaderboardAuraController.TrailblazerQueryConfig config = new TrailheadLeaderboardAuraController.TrailblazerQueryConfig(); + config.sortBy = 'Superbadges__c'; + List trailblazers = TrailheadLeaderboardAuraController.populateTrailblazers( + config + ); Test.stopTest(); // Assert @@ -88,7 +92,10 @@ private class TrailheadLeaderboardAuraControllerTest { System.assertEquals('success', resultString); System.assertEquals( 2, - TrailheadLeaderboardAuraController.populateTrailblazers('', null, null, null).size(), + TrailheadLeaderboardAuraController.populateTrailblazers( + new TrailheadLeaderboardAuraController.TrailblazerQueryConfig() + ) + .size(), 'Two Trailblazers should exist now.' ); } @@ -113,11 +120,18 @@ private class TrailheadLeaderboardAuraControllerTest { Test.stopTest(); // Assert - System.assertEquals(0, [SELECT Id FROM Trailblazer__c WHERE Profile_Handle__c = :'someId'].size(), - 'Test Trailblazer should not have been created.'); + System.assertEquals( + 0, + [SELECT Id FROM Trailblazer__c WHERE Profile_Handle__c = :'someId'].size(), + 'Test Trailblazer should not have been created.' + ); System.assertNotEquals('success', resultString); - System.assertEquals(2, - TrailheadLeaderboardAuraController.populateTrailblazers('', null, null, null).size(), + System.assertEquals( + 2, + TrailheadLeaderboardAuraController.populateTrailblazers( + new TrailheadLeaderboardAuraController.TrailblazerQueryConfig() + ) + .size(), 'Only the two Trailblazers should exist, \'someId\' should not have been created.' ); } @@ -138,8 +152,9 @@ private class TrailheadLeaderboardAuraControllerTest { // Act Test.startTest(); - List skills = - TrailheadLeaderboardAuraController.getSkillData('someId'); + List skills = TrailheadLeaderboardAuraController.getSkillData( + 'someId' + ); Test.stopTest(); // Assert @@ -167,12 +182,17 @@ private class TrailheadLeaderboardAuraControllerTest { // Act Test.startTest(); - List certifications = - TrailheadLeaderboardAuraController.getCertificationData('someId'); + List certifications = TrailheadLeaderboardAuraController.getCertificationData( + 'someId' + ); Test.stopTest(); // Assert - System.assertEquals(1, certifications.size(), 'One certification should have been returned.'); + System.assertEquals( + 1, + certifications.size(), + 'One certification should have been returned.' + ); for (CertificationData.certificationsList certification : certifications) { System.assertEquals(null, certification.dateExpired); @@ -210,18 +230,32 @@ private class TrailheadLeaderboardAuraControllerTest { Test.stopTest(); // Assert - System.assertEquals(3, earnedAwards.edges.size(), - 'Three badges should have been returned.'); - System.assertNotEquals(null, earnedAwards.pageInfo, - 'pageInfo should have been returned.'); - System.assertNotEquals(null, earnedAwards.pageInfo.hasNextPage, - 'hasNextPage should have been returned.'); - System.assertNotEquals(null, earnedAwards.pageInfo.startCursor, - 'startCursor should have been returned.'); - System.assertNotEquals(null, earnedAwards.pageInfo.endCursor, - 'endCursor should have been returned.'); - System.assertNotEquals(null, earnedAwards.pageInfo.hasPreviousPage, - 'hasPreviousPage should have been returned.'); + System.assertEquals( + 3, + earnedAwards.edges.size(), + 'Three badges should have been returned.' + ); + System.assertNotEquals(null, earnedAwards.pageInfo, 'pageInfo should have been returned.'); + System.assertNotEquals( + null, + earnedAwards.pageInfo.hasNextPage, + 'hasNextPage should have been returned.' + ); + System.assertNotEquals( + null, + earnedAwards.pageInfo.startCursor, + 'startCursor should have been returned.' + ); + System.assertNotEquals( + null, + earnedAwards.pageInfo.endCursor, + 'endCursor should have been returned.' + ); + System.assertNotEquals( + null, + earnedAwards.pageInfo.hasPreviousPage, + 'hasPreviousPage should have been returned.' + ); for (TrailheadGraphQlData.edges award : earnedAwards.edges) { System.assertNotEquals(null, award.node.award.content.webUrl); @@ -256,7 +290,10 @@ private class TrailheadLeaderboardAuraControllerTest { Test.stopTest(); // Assert - System.assertEquals(null, earnedAwards, - 'No badges should have been returned as the API failed to respond with data.'); + System.assertEquals( + null, + earnedAwards, + 'No badges should have been returned as the API failed to respond with data.' + ); } -} \ No newline at end of file +} diff --git a/force-app/main/default/lwc/alertMessage/alertMessage.html b/force-app/main/default/lwc/alertMessage/alertMessage.html index cfc072d..ed854b7 100644 --- a/force-app/main/default/lwc/alertMessage/alertMessage.html +++ b/force-app/main/default/lwc/alertMessage/alertMessage.html @@ -1,40 +1,36 @@ diff --git a/force-app/main/default/lwc/leaderboardBadges/leaderboardBadges.html b/force-app/main/default/lwc/leaderboardBadges/leaderboardBadges.html index 04f1e4c..502351c 100644 --- a/force-app/main/default/lwc/leaderboardBadges/leaderboardBadges.html +++ b/force-app/main/default/lwc/leaderboardBadges/leaderboardBadges.html @@ -1,94 +1,83 @@ diff --git a/force-app/main/default/lwc/leaderboardCertification/leaderboardCertification.html b/force-app/main/default/lwc/leaderboardCertification/leaderboardCertification.html index ec0bb9f..18395dd 100644 --- a/force-app/main/default/lwc/leaderboardCertification/leaderboardCertification.html +++ b/force-app/main/default/lwc/leaderboardCertification/leaderboardCertification.html @@ -1,51 +1,46 @@ \ No newline at end of file + + diff --git a/force-app/main/default/lwc/leaderboardCertifications/leaderboardCertifications.html b/force-app/main/default/lwc/leaderboardCertifications/leaderboardCertifications.html index 6276ca9..7f6eb48 100644 --- a/force-app/main/default/lwc/leaderboardCertifications/leaderboardCertifications.html +++ b/force-app/main/default/lwc/leaderboardCertifications/leaderboardCertifications.html @@ -1,52 +1,46 @@ \ No newline at end of file +
+ {noCertificationsMessage} +
+ + + diff --git a/force-app/main/default/lwc/leaderboardCertifications/leaderboardCertifications.js b/force-app/main/default/lwc/leaderboardCertifications/leaderboardCertifications.js index 8be4eb9..f3f074e 100644 --- a/force-app/main/default/lwc/leaderboardCertifications/leaderboardCertifications.js +++ b/force-app/main/default/lwc/leaderboardCertifications/leaderboardCertifications.js @@ -72,7 +72,7 @@ export default class LeaderboardCertifications extends LightningElement { } get noCertificationsMessage() { - return "No Salesforce certifications found for this Trailblazer. Does this Trailblazer have any certifications and have they connected Trailhead to Webassessor?"; + return "No Salesforce certifications found for this Trailblazer"; } get displayShowMore() { diff --git a/force-app/main/default/lwc/leaderboardHeader/leaderboardHeader.html b/force-app/main/default/lwc/leaderboardHeader/leaderboardHeader.html index 4bdb947..d294236 100644 --- a/force-app/main/default/lwc/leaderboardHeader/leaderboardHeader.html +++ b/force-app/main/default/lwc/leaderboardHeader/leaderboardHeader.html @@ -1,5 +1,7 @@ \ No newline at end of file +
+

Trailhead Leaderboard

+
+ diff --git a/force-app/main/default/lwc/leaderboardNewTrailblazerModal/leaderboardNewTrailblazerModal.html b/force-app/main/default/lwc/leaderboardNewTrailblazerModal/leaderboardNewTrailblazerModal.html index b2482f7..395e058 100644 --- a/force-app/main/default/lwc/leaderboardNewTrailblazerModal/leaderboardNewTrailblazerModal.html +++ b/force-app/main/default/lwc/leaderboardNewTrailblazerModal/leaderboardNewTrailblazerModal.html @@ -1,94 +1,91 @@ diff --git a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.css b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.css index 44c96c9..0d171f9 100644 --- a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.css +++ b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.css @@ -1 +1 @@ -@import "c/leaderboardStyles"; \ No newline at end of file +@import "c/leaderboardStyles"; diff --git a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.html b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.html index 03afdf9..d2d4892 100644 --- a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.html +++ b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.html @@ -1,15 +1,30 @@ diff --git a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js index 5d6658b..74cdda6 100644 --- a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js +++ b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js @@ -1,11 +1,59 @@ -import { LightningElement } from "lwc"; +import { LightningElement, api } from "lwc"; + +const PAGE_SIZE_OPTIONS = [ + { + label: "10", + value: "10" + }, + { + label: "15", + value: "15" + }, + { + label: "25", + value: "25" + } +]; export default class LeaderboardPagination extends LightningElement { + @api paginationData; + + get selectedPageSize() { + return this._selectedPageSize || this.paginationData.pageSize; + } + + set selectedPageSize(value) { + this._selectedPageSize = value; + } + + get pageSizeOptions() { + return PAGE_SIZE_OPTIONS; + } + + get previousDisabled() { + return this.paginationData.pageNumber === 1 ?? false; + } + + get nextDisabled() { + return ( + this.paginationData.pageNumber === this.paginationData.totalPages ?? false + ); + } + handlePrevious() { this.dispatchEvent(new CustomEvent("previous")); } + handlePageSizeChange(event) { + this.selectedPageSize = event.detail.value; + this.dispatchEvent( + new CustomEvent("pagesize", { + detail: parseInt(event.detail.value, 10) + }) + ); + } + handleNext() { this.dispatchEvent(new CustomEvent("next")); } -} \ No newline at end of file +} diff --git a/force-app/main/default/lwc/leaderboardProfileCard/leaderboardProfileCard.html b/force-app/main/default/lwc/leaderboardProfileCard/leaderboardProfileCard.html index ed73b5c..cad5d17 100644 --- a/force-app/main/default/lwc/leaderboardProfileCard/leaderboardProfileCard.html +++ b/force-app/main/default/lwc/leaderboardProfileCard/leaderboardProfileCard.html @@ -1,157 +1,153 @@ diff --git a/force-app/main/default/lwc/leaderboardProfileModal/leaderboardProfileModal.html b/force-app/main/default/lwc/leaderboardProfileModal/leaderboardProfileModal.html index b1751b8..9fcc93d 100644 --- a/force-app/main/default/lwc/leaderboardProfileModal/leaderboardProfileModal.html +++ b/force-app/main/default/lwc/leaderboardProfileModal/leaderboardProfileModal.html @@ -1,83 +1,71 @@ + diff --git a/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.html b/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.html index 5e0634a..9ef9101 100644 --- a/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.html +++ b/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.html @@ -1,85 +1,93 @@ \ No newline at end of file + +
{trailblazer.Certifications__c}
+ + + + + + diff --git a/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.js b/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.js index d3701fa..99dce84 100644 --- a/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.js +++ b/force-app/main/default/lwc/leaderboardProfileTableRow/leaderboardProfileTableRow.js @@ -1,27 +1,22 @@ -import { LightningElement, api, track } from "lwc"; +import { LightningElement, api } from "lwc"; +import LeaderboardProfileHelper from "c/leaderboardProfileHelper"; import LEADERBOARD_SOURCE from "@salesforce/resourceUrl/Trailhead_Leaderboard"; const profileHelper = new LeaderboardProfileHelper(); -import LeaderboardProfileHelper from "c/leaderboardProfileHelper"; export default class LeaderboardProfileTableRow extends LightningElement { @api trailblazer; - @api queryOffset = 0; + @api offset; + @api index; - @api - get index() { - return this._index; - } + photoError = false; - set index(value) { - this.setAttribute("index", value++); - this._index = value; + get rankNumber() { + return this.index + 1 + (isNaN(this.offset) ? 0 : this.offset); } - @track photoError = false; - get placeholderProfilePhotoURL() { - return LEADERBOARD_SOURCE + "/trailheadLeaderboard/astro.png"; + return `${LEADERBOARD_SOURCE}/trailheadLeaderboard/astro.png`; } get titleString() { diff --git a/force-app/main/default/lwc/leaderboardRank/leaderboardRank.html b/force-app/main/default/lwc/leaderboardRank/leaderboardRank.html index 30a8544..64cee8c 100644 --- a/force-app/main/default/lwc/leaderboardRank/leaderboardRank.html +++ b/force-app/main/default/lwc/leaderboardRank/leaderboardRank.html @@ -1,3 +1 @@ - \ No newline at end of file + diff --git a/force-app/main/default/lwc/leaderboardRankBadge/leaderboardRankBadge.html b/force-app/main/default/lwc/leaderboardRankBadge/leaderboardRankBadge.html index 8ee3297..883e86e 100644 --- a/force-app/main/default/lwc/leaderboardRankBadge/leaderboardRankBadge.html +++ b/force-app/main/default/lwc/leaderboardRankBadge/leaderboardRankBadge.html @@ -1,7 +1,12 @@ diff --git a/force-app/main/default/lwc/leaderboardRankBadge/leaderboardRankBadge.js b/force-app/main/default/lwc/leaderboardRankBadge/leaderboardRankBadge.js index 251ad3f..2626bfc 100644 --- a/force-app/main/default/lwc/leaderboardRankBadge/leaderboardRankBadge.js +++ b/force-app/main/default/lwc/leaderboardRankBadge/leaderboardRankBadge.js @@ -6,16 +6,7 @@ export default class LeaderboardRankBadge extends LightningElement { @api rankBadgeLink; @api showName = false; - get rankBadgeURL() { - return ( - LEADERBOARD_SOURCE + - "/trailheadLeaderboard/ranks/" + - this.rankName.toLowerCase() + - ".png" - ); - } - - get alt() { + get altTitle() { return this.rankName; } } diff --git a/force-app/main/default/lwc/leaderboardSkills/leaderboardSkills.html b/force-app/main/default/lwc/leaderboardSkills/leaderboardSkills.html index 7ddb24f..c009e88 100644 --- a/force-app/main/default/lwc/leaderboardSkills/leaderboardSkills.html +++ b/force-app/main/default/lwc/leaderboardSkills/leaderboardSkills.html @@ -1,30 +1,24 @@ \ No newline at end of file + + + diff --git a/force-app/main/default/lwc/leaderboardSortDir/leaderboardSortDir.html b/force-app/main/default/lwc/leaderboardSortDir/leaderboardSortDir.html index 6598ffa..11ea020 100644 --- a/force-app/main/default/lwc/leaderboardSortDir/leaderboardSortDir.html +++ b/force-app/main/default/lwc/leaderboardSortDir/leaderboardSortDir.html @@ -1,6 +1,18 @@ \ No newline at end of file + + + + + diff --git a/force-app/main/default/lwc/leaderboardSortDir/leaderboardSortDir.js b/force-app/main/default/lwc/leaderboardSortDir/leaderboardSortDir.js index 2d701b2..75acc42 100644 --- a/force-app/main/default/lwc/leaderboardSortDir/leaderboardSortDir.js +++ b/force-app/main/default/lwc/leaderboardSortDir/leaderboardSortDir.js @@ -1,11 +1,11 @@ -import { LightningElement, api, track } from "lwc"; +import { LightningElement, api } from "lwc"; export default class LeaderboardSortDir extends LightningElement { @api columnField; - @api fieldToSortBy; + @api sortBy; @api descending; get showSort() { - return this.columnField === this.fieldToSortBy; + return this.columnField === this.sortBy; } } diff --git a/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html b/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html index ea35d8a..540eead 100644 --- a/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html +++ b/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html @@ -10,18 +10,24 @@

- +
+
+ +
- + +
@@ -44,7 +50,7 @@

Name

@@ -60,7 +66,7 @@

Rank @@ -76,7 +82,7 @@

Points @@ -92,7 +98,7 @@

Badges @@ -108,7 +114,7 @@

Trails @@ -124,7 +130,7 @@

Superbadges @@ -140,7 +146,7 @@

Certifications @@ -162,6 +168,7 @@

key={trailblazer.Id} trailblazer={trailblazer} index={index} + offset={paginationData.offset} onopenmodal={showProfileModal} > @@ -195,7 +202,7 @@

{trailblazerCountString} -
{moreInfoText}
+ {moreInfoText}

@@ -226,24 +233,30 @@

-
- -
- -  /  - - meruff - -
-
+
+
+ + +
+ +  /  + + meruff + +
+
0 - ? `${this.trailblazers.length} Trailblazers` + return this.trailblazerCount + ? `${this.trailblazerCount} Trailblazers` : "All Trailblazers"; } @@ -43,8 +46,8 @@ export default class LeaderboardTable extends LightningElement { } handleSort(event) { - if (this.fieldToSortBy !== event.target.dataset.field) { - this.fieldToSortBy = event.target.dataset.field; + if (this.sortBy !== event.target.dataset.field) { + this.sortBy = event.target.dataset.field; this.descending = true; } else { this.descending = !this.descending; @@ -53,7 +56,7 @@ export default class LeaderboardTable extends LightningElement { this.dispatchEvent( new CustomEvent("sort", { detail: { - fieldToSortBy: this.fieldToSortBy, + fieldToSortBy: this.sortBy, descending: this.descending } }) @@ -64,10 +67,18 @@ export default class LeaderboardTable extends LightningElement { this.dispatchEvent(new CustomEvent("previous")); } + handlePageSize(event) { + this.dispatchEvent(new CustomEvent("pagesize", { detail: event.detail })); + } + handleNext() { this.dispatchEvent(new CustomEvent("next")); } + handleShowMore() { + this.dispatchEvent(new CustomEvent("showmore")); + } + fireRefresh() { this.dispatchEvent(new CustomEvent("refreshtable")); } diff --git a/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.html b/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.html index 2638e20..2112054 100644 --- a/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.html +++ b/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.html @@ -2,11 +2,16 @@
diff --git a/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js b/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js index 2f810bf..7f55183 100644 --- a/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js +++ b/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js @@ -1,9 +1,9 @@ import { LightningElement, wire } from "lwc"; -import populateTrailblazers from "@salesforce/apex/TrailheadLeaderboardAuraController.populateTrailblazers"; import { refreshApex } from "@salesforce/apex"; +import populateTrailblazers from "@salesforce/apex/TrailheadLeaderboardAuraController.populateTrailblazers"; +import getTotalTrailblazerCount from "@salesforce/apex/TrailheadLeaderboardAuraController.getTotalTrailblazerCount"; const DEFAULT_PAGE_SIZE = 10; -const DEFAULT_PAGE_NUMBER = 1; export default class TrailheadLeaderboard extends LightningElement { sortBy = "Points__c"; @@ -16,20 +16,26 @@ export default class TrailheadLeaderboard extends LightningElement { }) trailblazers; - get pageNumber() { - if (!this._pageNumber) { - return DEFAULT_PAGE_NUMBER; - } + @wire(getTotalTrailblazerCount) + totalTrailblazerCount; + + get showTable() { + return this.trailblazers.data && this.totalTrailblazerCount.data; + } - return this._pageNumber; + get pageNumber() { + return this._pageNumber || 1; } set pageNumber(value) { this._pageNumber = value; - this.offset = - this._pageNumber > 1 ? --this._pageNumber * this.pageSize : null; + this.offset = value > 1 ? (value - 1) * this.pageSize : null; } + /** + * Formats filter, sort, and page data in an easily consumable config Object. + * @returns {{offset: null, pageSize: number, sortBy: string, descending: boolean}} + */ get queryOptions() { return { sortBy: this.sortBy, @@ -39,28 +45,62 @@ export default class TrailheadLeaderboard extends LightningElement { }; } + /** + * Formats page number, size, and offset into consumable config object. + * @returns {{pageNumber: *, offset: null, pageSize: string}} + */ + get paginationData() { + return { + totalPages: this.totalPages, + pageNumber: this.pageNumber, + pageSize: this.selectOptionPageSize, + offset: this.offset + }; + } + + get totalTrailblazers() { + return this.totalTrailblazerCount?.data ?? 0; + } + + get totalPages() { + return Math.ceil(this.totalTrailblazers / this.pageSize); + } + + get selectOptionPageSize() { + return "" + this.pageSize; + } + handleSort(event) { this.sortBy = event.detail.fieldToSortBy; this.descending = event.detail.descending; } handlePrevious() { - console.log("prev"); - this.pageNumber = this.pageNumber !== 1 ? this.pageNumber-- : 1; + const currentPageNumber = this.pageNumber; + this.pageNumber = currentPageNumber !== 1 ? currentPageNumber - 1 : 1; } handleNext() { - console.log("next"); - // TODO: Some logic here to determine not going past max pages. - this.pageNumber++; + const currentPageNumber = this.pageNumber; + this.pageNumber = + currentPageNumber < this.totalPages + ? currentPageNumber + 1 + : this.totalPages; + } + + handleShowMore() { + this.pageSize += DEFAULT_PAGE_SIZE; } - handleSetPageSize(event) { - console.log(event.detail); + handlePageSize(event) { + this.pageNumber = 1; this.pageSize = event.detail; } refresh() { - return refreshApex(this.trailblazers); + Promise.all([ + refreshApex(this.trailblazers), + refreshApex(this.totalTrailblazerCount) + ]).then(); } } diff --git a/force-app/main/default/pages/trailheadLeaderboard.page b/force-app/main/default/pages/trailheadLeaderboard.page index 6923444..1293e4f 100644 --- a/force-app/main/default/pages/trailheadLeaderboard.page +++ b/force-app/main/default/pages/trailheadLeaderboard.page @@ -10,11 +10,6 @@ name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" /> - false true - https://go-trailhead-leaderboard-api.herokuapp.com + https://go-trailhead-leaderboard-api.up.railway.app diff --git a/package.json b/package.json index d1de193..bff2807 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,6 @@ "prettier-plugin-apex": "1.10.0" }, "scripts": { - "prettier": "prettier --write '**/*.{css,js}'" + "prettier": "prettier --write 'force-app/**/*.{cls,apex,css,js,html}'" } } From 5bf96c47931b36a97215c22e7919c093a2ded19f Mon Sep 17 00:00:00 2001 From: meruff Date: Sat, 3 Sep 2022 14:20:22 -0700 Subject: [PATCH 3/4] Add show more button for mobile, count at top for desktop. Cleanup/formatting. --- README.md | 2 +- .../default/classes/CertificationData.cls | 9 +++-- .../classes/GetTrailblazerInfoAsync.cls | 2 +- .../main/default/classes/ProfileData.cls | 4 +- .../default/classes/TrailheadGraphQlData.cls | 40 +++++++++---------- .../TrailheadLeaderboardAuraController.cls | 6 +-- ...TrailheadLeaderboardAuraControllerTest.cls | 14 +++---- .../leaderboardPagination.js | 12 ++++-- .../leaderboardTable/leaderboardTable.html | 3 +- .../lwc/leaderboardTable/leaderboardTable.js | 27 ++++++++++++- .../trailheadLeaderboard.js | 2 +- 11 files changed, 76 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 7be2a14..414bcdb 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ finished. - ~~Convert to Salesforce DX Project~~ - ~~Add a custom Trailhead API~~ - ~~Dark mode~~ -- Pagination / loading more. +- ~~Pagination / loading more.~~ - Handle deactivating Trailblazers who go private / 404. - Remove `Badge__c`. diff --git a/force-app/main/default/classes/CertificationData.cls b/force-app/main/default/classes/CertificationData.cls index 998e858..bec3631 100644 --- a/force-app/main/default/classes/CertificationData.cls +++ b/force-app/main/default/classes/CertificationData.cls @@ -1,16 +1,17 @@ /** + * @description A class to deserialize Trailhead Certification data from the API into. + * * @author meruff - * @date 3/18/20 * - * A class to deserialize Trailhead Certification data from the API into. + * @date 3/18/20 */ public class CertificationData { public String error { get; set; } @AuraEnabled - public List certificationsList { get; set; } + public List certificationsList { get; set; } - public class certificationsList { + public class CertificationsList { @AuraEnabled public String dateExpired { get; set; } diff --git a/force-app/main/default/classes/GetTrailblazerInfoAsync.cls b/force-app/main/default/classes/GetTrailblazerInfoAsync.cls index 857fe61..b26262b 100644 --- a/force-app/main/default/classes/GetTrailblazerInfoAsync.cls +++ b/force-app/main/default/classes/GetTrailblazerInfoAsync.cls @@ -164,7 +164,7 @@ public class GetTrailblazerInfoAsync implements Queueable, Database.AllowsCallou if (data.profile?.earnedAwards?.edges != null) { Integer count = 0; - for (TrailheadGraphQlData.edges edge : data.profile?.earnedAwards?.edges) { + for (TrailheadGraphQlData.Edges edge : data.profile?.earnedAwards?.edges) { if (edge.node.award.type == 'SUPERBADGE') { count++; } diff --git a/force-app/main/default/classes/ProfileData.cls b/force-app/main/default/classes/ProfileData.cls index e062762..f7d50c9 100644 --- a/force-app/main/default/classes/ProfileData.cls +++ b/force-app/main/default/classes/ProfileData.cls @@ -8,9 +8,9 @@ public class ProfileData { public String error { get; set; } public String profilePhotoUrl { get; set; } - public profileUser profileUser { get; set; } + public ProfileUser profileUser { get; set; } - public class profileUser { + public class ProfileUser { public String TBID_Role { get; set; } public String CompanyName { get; set; } public String TrailblazerId { get; set; } diff --git a/force-app/main/default/classes/TrailheadGraphQlData.cls b/force-app/main/default/classes/TrailheadGraphQlData.cls index 4cc0bbf..6d93e3f 100644 --- a/force-app/main/default/classes/TrailheadGraphQlData.cls +++ b/force-app/main/default/classes/TrailheadGraphQlData.cls @@ -13,44 +13,44 @@ public class TrailheadGraphQlData { public class Profile { @AuraEnabled - public trailheadStats trailheadStats { get; set; } + public TrailheadStats trailheadStats { get; set; } @AuraEnabled - public List earnedSkills { get; set; } + public List earnedSkills { get; set; } @AuraEnabled - public earnedAwards earnedAwards { get; set; } + public EarnedAwards earnedAwards { get; set; } } // Rank data - public class trailheadStats { + public class TrailheadStats { public Integer completedTrailCount { get; set; } public Integer earnedBadgesCount { get; set; } - public rank rank { get; set; } + public Rank rank { get; set; } public Integer earnedPointsSum { get; set; } } - public class rank { + public class Rank { public String imageUrl { get; set; } public String title { get; set; } } // Skill data - public class skill { + public class Skill { @AuraEnabled public String name { get; set; } } - public class earnedSkills { + public class EarnedSkills { @AuraEnabled public Integer earnedPointsSum { get; set; } @AuraEnabled - public skill skill { get; set; } + public Skill skill { get; set; } } // Badge data - public class pageInfo { + public class PageInfo { @AuraEnabled public Boolean hasNextPage { get; set; } @@ -64,9 +64,9 @@ public class TrailheadGraphQlData { public Boolean hasPreviousPage { get; set; } } - public class node { + public class Node { @AuraEnabled - public award award { get; set; } + public Award award { get; set; } @AuraEnabled public String earnedAt { get; set; } @@ -75,25 +75,25 @@ public class TrailheadGraphQlData { public String earnedPointsSum { get; set; } } - public class edges { + public class Edges { @AuraEnabled - public node node { get; set; } + public Node node { get; set; } } - public class earnedAwards { + public class EarnedAwards { @AuraEnabled - public pageInfo pageInfo { get; set; } + public PageInfo pageInfo { get; set; } @AuraEnabled - public List edges { get; set; } + public List edges { get; set; } } - public class content { + public class Content { @AuraEnabled public String webUrl { get; set; } } - public class award { + public class Award { @AuraEnabled public String icon { get; set; } @@ -107,6 +107,6 @@ public class TrailheadGraphQlData { public String id { get; set; } @AuraEnabled - public content content { get; set; } + public Content content { get; set; } } } diff --git a/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls b/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls index fa8ccea..e4064b1 100644 --- a/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls +++ b/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls @@ -123,7 +123,7 @@ public without sharing class TrailheadLeaderboardAuraController { * @return a TrailheadGraphQlData.earnedAwards record. */ @AuraEnabled - public static TrailheadGraphQlData.earnedAwards getBadgeData( + public static TrailheadGraphQlData.EarnedAwards getBadgeData( String userId, String filter, Integer count, @@ -174,7 +174,7 @@ public without sharing class TrailheadLeaderboardAuraController { * @return a List of TrailheadGraphQlData.earnedSkills records. */ @AuraEnabled - public static List getSkillData(String userId) { + public static List getSkillData(String userId) { String resBody = TrailheadHelper.doCallout( TrailheadHelper.GO_TRAILHEAD_API + userId + @@ -205,7 +205,7 @@ public without sharing class TrailheadLeaderboardAuraController { * @return a List of CertificationData.certificationsList records. */ @AuraEnabled - public static List getCertificationData(String userId) { + public static List getCertificationData(String userId) { String resBody = TrailheadHelper.doCallout( TrailheadHelper.GO_TRAILHEAD_API + userId + diff --git a/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls b/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls index 6c08fd6..d815325 100644 --- a/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls +++ b/force-app/main/default/classes/TrailheadLeaderboardAuraControllerTest.cls @@ -152,7 +152,7 @@ private class TrailheadLeaderboardAuraControllerTest { // Act Test.startTest(); - List skills = TrailheadLeaderboardAuraController.getSkillData( + List skills = TrailheadLeaderboardAuraController.getSkillData( 'someId' ); Test.stopTest(); @@ -160,7 +160,7 @@ private class TrailheadLeaderboardAuraControllerTest { // Assert System.assertEquals(2, skills.size(), 'Two skills should have been returned.'); - for (TrailheadGraphQlData.earnedSkills skill : skills) { + for (TrailheadGraphQlData.EarnedSkills skill : skills) { System.assertNotEquals(null, skill.skill.name); System.assertNotEquals(null, skill.earnedPointsSum); } @@ -182,7 +182,7 @@ private class TrailheadLeaderboardAuraControllerTest { // Act Test.startTest(); - List certifications = TrailheadLeaderboardAuraController.getCertificationData( + List certifications = TrailheadLeaderboardAuraController.getCertificationData( 'someId' ); Test.stopTest(); @@ -194,7 +194,7 @@ private class TrailheadLeaderboardAuraControllerTest { 'One certification should have been returned.' ); - for (CertificationData.certificationsList certification : certifications) { + for (CertificationData.CertificationsList certification : certifications) { System.assertEquals(null, certification.dateExpired); System.assertNotEquals(null, certification.dateCompleted); System.assertNotEquals(null, certification.description); @@ -221,7 +221,7 @@ private class TrailheadLeaderboardAuraControllerTest { // Act Test.startTest(); - TrailheadGraphQlData.earnedAwards earnedAwards = TrailheadLeaderboardAuraController.getBadgeData( + TrailheadGraphQlData.EarnedAwards earnedAwards = TrailheadLeaderboardAuraController.getBadgeData( 'someId', 'all', 16, @@ -257,7 +257,7 @@ private class TrailheadLeaderboardAuraControllerTest { 'hasPreviousPage should have been returned.' ); - for (TrailheadGraphQlData.edges award : earnedAwards.edges) { + for (TrailheadGraphQlData.Edges award : earnedAwards.edges) { System.assertNotEquals(null, award.node.award.content.webUrl); System.assertNotEquals(null, award.node.award.title); System.assertNotEquals(null, award.node.award.icon); @@ -281,7 +281,7 @@ private class TrailheadLeaderboardAuraControllerTest { // Act Test.startTest(); - TrailheadGraphQlData.earnedAwards earnedAwards = TrailheadLeaderboardAuraController.getBadgeData( + TrailheadGraphQlData.EarnedAwards earnedAwards = TrailheadLeaderboardAuraController.getBadgeData( 'someId', 'all', null, diff --git a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js index 74cdda6..3364ec6 100644 --- a/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js +++ b/force-app/main/default/lwc/leaderboardPagination/leaderboardPagination.js @@ -2,16 +2,20 @@ import { LightningElement, api } from "lwc"; const PAGE_SIZE_OPTIONS = [ { - label: "10", - value: "10" + label: "5", + value: "5" }, { label: "15", value: "15" }, { - label: "25", - value: "25" + label: "30", + value: "30" + }, + { + label: "50", + value: "50" } ]; diff --git a/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html b/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html index 540eead..c2b9a4f 100644 --- a/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html +++ b/force-app/main/default/lwc/leaderboardTable/leaderboardTable.html @@ -5,7 +5,7 @@

{trailblazerCountString} -
{moreInfoText} +
{desktopCountText}

@@ -234,6 +234,7 @@

diff --git a/force-app/main/default/lwc/leaderboardTable/leaderboardTable.js b/force-app/main/default/lwc/leaderboardTable/leaderboardTable.js index bb3dc75..751b904 100644 --- a/force-app/main/default/lwc/leaderboardTable/leaderboardTable.js +++ b/force-app/main/default/lwc/leaderboardTable/leaderboardTable.js @@ -19,14 +19,39 @@ export default class LeaderboardTable extends LightningElement { : "All Trailblazers"; } + get desktopCountText() { + return `Showing ${this.startCount}-${this.endCount} of ${this.trailblazerCount} • ${this.moreInfoText}`; + } + get moreInfoText() { - return "Click on a Trailblazer for more info."; + return `Click on a Trailblazer for more info`; + } + + get startCount() { + return 1 + this.offset; + } + + get endCount() { + const endCount = this.pageSize + this.offset; + return endCount <= this.trailblazerCount ? endCount : this.trailblazerCount; + } + + get offset() { + return this.paginationData.offset ?? 0; + } + + get pageSize() { + return parseInt(this.paginationData.pageSize) ?? 0; } get githubLogoUrl() { return `${LEADERBOARD_SOURCE}/trailheadLeaderboard/github.svg`; } + get showMoreButton() { + return this.paginationData.pageSize <= this.trailblazerCount; + } + showProfileModal(event) { this.selectedTrailblazerId = event.detail.trailblazerId; this.selectedTrailblazerHandle = event.detail.trailblazerHandle; diff --git a/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js b/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js index 7f55183..266fe32 100644 --- a/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js +++ b/force-app/main/default/lwc/trailheadLeaderboard/trailheadLeaderboard.js @@ -3,7 +3,7 @@ import { refreshApex } from "@salesforce/apex"; import populateTrailblazers from "@salesforce/apex/TrailheadLeaderboardAuraController.populateTrailblazers"; import getTotalTrailblazerCount from "@salesforce/apex/TrailheadLeaderboardAuraController.getTotalTrailblazerCount"; -const DEFAULT_PAGE_SIZE = 10; +const DEFAULT_PAGE_SIZE = 15; export default class TrailheadLeaderboard extends LightningElement { sortBy = "Points__c"; From 62f940e5ee24ce107e1ed86e08bec7fd3bb8dc08 Mon Sep 17 00:00:00 2001 From: meruff Date: Sun, 4 Sep 2022 13:55:15 -0700 Subject: [PATCH 4/4] Update controller logic for new config. --- .../default/classes/TrailheadLeaderboardAuraController.cls | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls b/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls index e4064b1..6875bf4 100644 --- a/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls +++ b/force-app/main/default/classes/TrailheadLeaderboardAuraController.cls @@ -31,10 +31,10 @@ public without sharing class TrailheadLeaderboardAuraController { } else { queryString += ' ORDER BY ' + options.sortBy; - if (options.descending == null || options.descending) { - queryString += ' DESC'; - } else { + if (options.descending == null || !options.descending) { queryString += ' ASC'; + } else { + queryString += ' DESC'; } }