From f02ef4a1d7dc57f91c9aea2555ad0af3e334c933 Mon Sep 17 00:00:00 2001 From: Daniel Bloxham Date: Thu, 15 Jul 2021 12:26:47 +0100 Subject: [PATCH 1/6] HEEDLS-431 - Populated course setup cards --- .../DataServices/CourseDataServiceTests.cs | 5 +- .../DataServices/CourseDataService.cs | 6 +- .../Models/Courses/CourseStatistics.cs | 3 + .../DigitalLearningSolutions.Web.csproj | 2 + .../Helpers/ConfigHelper.cs | 1 + .../FilterOptions/CourseFilterOptions.cs | 42 ++++++++++++++ .../Helpers/FilterableTagHelper.cs | 30 +++++++++- .../trackingSystem/centreCourseSetup.ts | 54 ++++++++++++++++++ .../Styles/index.scss | 8 +++ .../Styles/learningMenu/contentViewer.scss | 8 --- .../SearchableCourseStatisticsViewModel.cs | 17 +++++- .../TrackingSystem/CourseSetup/Index.cshtml | 7 ++- .../CourseSetup/_CentreCourseCard.cshtml | 56 +++++++++++++++++++ 13 files changed, 225 insertions(+), 14 deletions(-) create mode 100644 DigitalLearningSolutions.Web/Helpers/FilterOptions/CourseFilterOptions.cs create mode 100644 DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts diff --git a/DigitalLearningSolutions.Data.Tests/DataServices/CourseDataServiceTests.cs b/DigitalLearningSolutions.Data.Tests/DataServices/CourseDataServiceTests.cs index 91613e27d3..5e04b9b019 100644 --- a/DigitalLearningSolutions.Data.Tests/DataServices/CourseDataServiceTests.cs +++ b/DigitalLearningSolutions.Data.Tests/DataServices/CourseDataServiceTests.cs @@ -239,7 +239,10 @@ public void GetCourseStatisticsAtCentreForCategoryID_should_return_course_statis DelegateCount = 25, AllAttempts = 49, AttemptsPassed = 34, - CompletedCount = 5 + CompletedCount = 5, + HideInLearnerPortal = false, + CategoryName = "Office 2007", + LearningMinutes = "N/A" }; result.Should().HaveCount(260); diff --git a/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs b/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs index c7a48a6028..9eb65f2d3c 100644 --- a/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs @@ -170,10 +170,14 @@ public IEnumerable GetCourseStatisticsAtCentreForCategoryId(in {DelegateCountQuery}, {CompletedCountQuery}, {AllAttemptsQuery}, - {AttemptsPassedQuery} + {AttemptsPassedQuery}, + cu.HideInLearnerPortal, + cc.CategoryName, + cu.LearningTimeMins AS LearningMinutes FROM dbo.Customisations AS cu INNER JOIN dbo.CentreApplications AS ca ON ca.ApplicationID = cu.ApplicationID INNER JOIN dbo.Applications AS ap ON ap.ApplicationID = ca.ApplicationID + INNER JOIN dbo.CourseCategories AS cc ON cc.CourseCategoryID = ap.CourseCategoryID WHERE (ap.CourseCategoryID = @categoryId OR @categoryId = 0) AND (cu.CentreID = @centreId OR (cu.AllCentres = 1 AND ca.Active = 1)) AND ca.CentreID = @centreId diff --git a/DigitalLearningSolutions.Data/Models/Courses/CourseStatistics.cs b/DigitalLearningSolutions.Data/Models/Courses/CourseStatistics.cs index 53092894e1..9b5831c9ef 100644 --- a/DigitalLearningSolutions.Data/Models/Courses/CourseStatistics.cs +++ b/DigitalLearningSolutions.Data/Models/Courses/CourseStatistics.cs @@ -15,6 +15,9 @@ public class CourseStatistics public int InProgressCount => DelegateCount - CompletedCount; public int AllAttempts { get; set; } public int AttemptsPassed { get; set; } + public bool HideInLearnerPortal { get; set; } + public string CategoryName { get; set; } + public string LearningMinutes { get; set; } public string CourseName => string.IsNullOrWhiteSpace(CustomisationName) ? ApplicationName diff --git a/DigitalLearningSolutions.Web/DigitalLearningSolutions.Web.csproj b/DigitalLearningSolutions.Web/DigitalLearningSolutions.Web.csproj index f90d3b2b01..e43e900ada 100644 --- a/DigitalLearningSolutions.Web/DigitalLearningSolutions.Web.csproj +++ b/DigitalLearningSolutions.Web/DigitalLearningSolutions.Web.csproj @@ -37,6 +37,7 @@ + @@ -94,6 +95,7 @@ + diff --git a/DigitalLearningSolutions.Web/Helpers/ConfigHelper.cs b/DigitalLearningSolutions.Web/Helpers/ConfigHelper.cs index da723a509a..63e0c94c94 100644 --- a/DigitalLearningSolutions.Web/Helpers/ConfigHelper.cs +++ b/DigitalLearningSolutions.Web/Helpers/ConfigHelper.cs @@ -10,6 +10,7 @@ public static class ConfigHelper public const string DefaultConnectionStringName = "DefaultConnection"; public const string UnitTestConnectionStringName = "UnitTestConnection"; public const string CurrentSystemBaseUrlName = "CurrentSystemBaseUrl"; + public const string AppRootPathName = "AppRootPath"; public const string MapsApiKey = "MapsAPIKey"; public static IConfigurationRoot GetAppConfig() diff --git a/DigitalLearningSolutions.Web/Helpers/FilterOptions/CourseFilterOptions.cs b/DigitalLearningSolutions.Web/Helpers/FilterOptions/CourseFilterOptions.cs new file mode 100644 index 0000000000..d3b66cd189 --- /dev/null +++ b/DigitalLearningSolutions.Web/Helpers/FilterOptions/CourseFilterOptions.cs @@ -0,0 +1,42 @@ +namespace DigitalLearningSolutions.Web.Helpers.FilterOptions +{ + using DigitalLearningSolutions.Data.Models.Courses; + using DigitalLearningSolutions.Web.Models.Enums; + using DigitalLearningSolutions.Web.ViewModels.Common.SearchablePage; + + public static class CourseActiveStatusFilterOptions + { + private const string Group = "ActiveStatus"; + + public static readonly FilterOptionViewModel IsInactive = new FilterOptionViewModel( + "Inactive", + Group + FilteringHelper.Separator + nameof(CourseStatistics.Active) + FilteringHelper.Separator + "false", + FilterStatus.Warning + ); + + public static readonly FilterOptionViewModel IsActive = new FilterOptionViewModel( + "Active", + Group + FilteringHelper.Separator + nameof(CourseStatistics.Active) + FilteringHelper.Separator + "true", + FilterStatus.Success + ); + } + + public static class CourseHiddenInLearningPortalStatusFilterOptions + { + private const string Group = "HiddenInLearningPortalStatus"; + + public static readonly FilterOptionViewModel IsHidden = new FilterOptionViewModel( + "Hidden in Learning Portal", + Group + FilteringHelper.Separator + nameof(CourseStatistics.HideInLearnerPortal) + + FilteringHelper.Separator + "true", + FilterStatus.Warning + ); + + public static readonly FilterOptionViewModel IsNotHidden = new FilterOptionViewModel( + "Visible in Learning Portal", + Group + FilteringHelper.Separator + nameof(CourseStatistics.HideInLearnerPortal) + + FilteringHelper.Separator + "true", + FilterStatus.Success + ); + } +} diff --git a/DigitalLearningSolutions.Web/Helpers/FilterableTagHelper.cs b/DigitalLearningSolutions.Web/Helpers/FilterableTagHelper.cs index 477f3173c5..3222030fb8 100644 --- a/DigitalLearningSolutions.Web/Helpers/FilterableTagHelper.cs +++ b/DigitalLearningSolutions.Web/Helpers/FilterableTagHelper.cs @@ -1,6 +1,7 @@ namespace DigitalLearningSolutions.Web.Helpers { using System.Collections.Generic; + using DigitalLearningSolutions.Data.Models.Courses; using DigitalLearningSolutions.Data.Models.User; using DigitalLearningSolutions.Web.Helpers.FilterOptions; using DigitalLearningSolutions.Web.ViewModels.Common.SearchablePage; @@ -10,7 +11,7 @@ public static class FilterableTagHelper public static IEnumerable GetCurrentTagsForAdminUser(AdminUser adminUser) { var tags = new List(); - + if (adminUser.IsLocked) { tags.Add(new SearchableTagViewModel(AdminAccountStatusFilterOptions.IsLocked)); @@ -52,5 +53,32 @@ public static IEnumerable GetCurrentTagsForAdminUser(Adm return tags; } + + public static IEnumerable GetCurrentTagsForCourseStatistics( + CourseStatistics courseStatistics + ) + { + var tags = new List(); + + if (courseStatistics.Active) + { + tags.Add(new SearchableTagViewModel(CourseActiveStatusFilterOptions.IsActive)); + } + else + { + tags.Add(new SearchableTagViewModel(CourseActiveStatusFilterOptions.IsInactive)); + } + + if (courseStatistics.HideInLearnerPortal) + { + tags.Add(new SearchableTagViewModel(CourseHiddenInLearningPortalStatusFilterOptions.IsHidden)); + } + else + { + tags.Add(new SearchableTagViewModel(CourseHiddenInLearningPortalStatusFilterOptions.IsNotHidden)); + } + + return tags; + } } } diff --git a/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts b/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts new file mode 100644 index 0000000000..f847873b0b --- /dev/null +++ b/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts @@ -0,0 +1,54 @@ +const copyCourseLinkClass = 'copy-course-link'; +const copyLinkIdPrefix = 'copy-course-'; +const launchCourseButtonIdPrefix = 'launch-course-'; + +setupCourseLinkClipboardCopiers(); + +function setupCourseLinkClipboardCopiers() { + const copyCourseLinks = document.getElementsByClassName(copyCourseLinkClass); + + for (let i = 0; i < copyCourseLinks.length; i += 1) { + const currentLink = copyCourseLinks[i]; + const linkId = currentLink.id; + const customisationId = linkId.slice(copyLinkIdPrefix.length); + + currentLink.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + copyLaunchCourseLinkToClipboard(customisationId); + }); + } +} + +function copyLaunchCourseLinkToClipboard(customisationId: string) { + const launchCourseButtonId = launchCourseButtonIdPrefix + customisationId; + const copyText = document.getElementById(launchCourseButtonId) as HTMLAnchorElement; + const link = copyText.href; + const succeeded = copyTextToClipboard(link); + let alertMessage: string; + + if (succeeded) { + alertMessage = `Copied the text: ${link}`; + } else { + alertMessage = `Copy not supported or blocked. Try manually selecting and copying: ${link}`; + } + + alert(alertMessage); +} + +function copyTextToClipboard(textToCopy: string) : boolean { + const hiddenInput = document.body.appendChild(document.createElement('input')); + hiddenInput.value = textToCopy; + hiddenInput.select(); + hiddenInput.setSelectionRange(0, textToCopy.length); + let succeeded: boolean; + + try { + succeeded = document.execCommand('copy'); + } catch (e) { + succeeded = false; + } + + document.body.removeChild(hiddenInput); + return succeeded; +} diff --git a/DigitalLearningSolutions.Web/Styles/index.scss b/DigitalLearningSolutions.Web/Styles/index.scss index 0e441992eb..3919fd7784 100644 --- a/DigitalLearningSolutions.Web/Styles/index.scss +++ b/DigitalLearningSolutions.Web/Styles/index.scss @@ -45,6 +45,14 @@ ul > li > ul > li { display: block; } +.js-only-inline { + display: none; +} + +.js-enabled .js-only-inline { + display: inline; +} + .small-edit-button, a.small-edit-button { margin-bottom: nhsuk-spacing(2); margin-top: nhsuk-spacing(0); diff --git a/DigitalLearningSolutions.Web/Styles/learningMenu/contentViewer.scss b/DigitalLearningSolutions.Web/Styles/learningMenu/contentViewer.scss index 5e28c1b83a..95c0a4dfd1 100644 --- a/DigitalLearningSolutions.Web/Styles/learningMenu/contentViewer.scss +++ b/DigitalLearningSolutions.Web/Styles/learningMenu/contentViewer.scss @@ -33,11 +33,3 @@ .hidden { display: none !important; } - -.js-only-inline { - display: none; -} - -.js-enabled .js-only-inline { - display: inline; -} diff --git a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs index 7311b4d726..c9f8067789 100644 --- a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs @@ -1,8 +1,10 @@ namespace DigitalLearningSolutions.Web.ViewModels.TrackingSystem.CourseSetup { using DigitalLearningSolutions.Data.Models.Courses; + using DigitalLearningSolutions.Web.Helpers; + using DigitalLearningSolutions.Web.ViewModels.Common.SearchablePage; - public class SearchableCourseStatisticsViewModel + public class SearchableCourseStatisticsViewModel : BaseFilterableViewModel { public SearchableCourseStatisticsViewModel(CourseStatistics courseStatistics) { @@ -14,6 +16,10 @@ public SearchableCourseStatisticsViewModel(CourseStatistics courseStatistics) InProgressCount = courseStatistics.InProgressCount; PassRate = courseStatistics.PassRate; CourseName = courseStatistics.CourseName; + HideInLearnerPortal = courseStatistics.HideInLearnerPortal; + CategoryName = courseStatistics.CategoryName; + LearningMinutes = courseStatistics.LearningMinutes; + Tags = FilterableTagHelper.GetCurrentTagsForCourseStatistics(courseStatistics); } public int CustomisationId { get; set; } @@ -24,5 +30,14 @@ public SearchableCourseStatisticsViewModel(CourseStatistics courseStatistics) public int InProgressCount { get; set; } public string CourseName { get; set; } public double PassRate { get; set; } + public bool HideInLearnerPortal { get; set; } + public string CategoryName { get; set; } + public string LearningMinutes { get; set; } + public string GenerateEmailHref => $"mailto:?subject={GenerateEmailSubject}&body={GenerateEmailContent}"; + private string GenerateEmailSubject => $"Digital Learning Solutions Course Link - {CourseName}"; + private string GenerateEmailContent => $"To start your {CourseName} course, click {LaunchCourseLink}"; + + private string LaunchCourseLink => + $"{ConfigHelper.GetAppConfig()[ConfigHelper.AppRootPathName]}/LearningMenu/{CustomisationId}"; } } diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/Index.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/Index.cshtml index dc77129c8e..a5e4f51349 100644 --- a/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/Index.cshtml +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/Index.cshtml @@ -4,7 +4,6 @@ @model CourseSetupViewModel - @{ ViewData["Title"] = "Centre course setup"; ViewData["Application"] = "Tracking System"; @@ -25,10 +24,14 @@ } else {
@foreach (var course in Model.Courses) { - + }
} + +@section scripts { + +} diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml index c01d5145ad..56bcfc4502 100644 --- a/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml @@ -8,7 +8,62 @@ @Model.CourseName +
+ + +
+
+
+ Category +
+
+ @Model.CategoryName +
+
+ +
+
+ Learning minutes +
+
+ @Model.LearningMinutes +
+
+ +
+
+ Total delegates +
+
+ @Model.DelegateCount +
+
+ +
+
+ In progress +
+
+ @Model.InProgressCount +
+
+ +
+ +
+
+

Want to share the course?

+ Generate email +
+ +
+
+
+ Copy course link +

To share this course with others, click Launch Course and copy the URL to the clipboard.

+
+
@@ -17,6 +72,7 @@
From fd60274102a57238c6c457a54070d5e3cd6f0fae Mon Sep 17 00:00:00 2001 From: Daniel Bloxham Date: Thu, 15 Jul 2021 16:48:01 +0100 Subject: [PATCH 2/6] HEEDLS-431 - Remove unused properties from view model --- .../CourseSetup/SearchableCourseStatisticsViewModel.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs index c9f8067789..136ddaacb6 100644 --- a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs @@ -9,28 +9,18 @@ public class SearchableCourseStatisticsViewModel : BaseFilterableViewModel public SearchableCourseStatisticsViewModel(CourseStatistics courseStatistics) { CustomisationId = courseStatistics.CustomisationId; - CentreId = courseStatistics.CentreId; - Active = courseStatistics.Active; DelegateCount = courseStatistics.DelegateCount; - CompletedCount = courseStatistics.CompletedCount; InProgressCount = courseStatistics.InProgressCount; - PassRate = courseStatistics.PassRate; CourseName = courseStatistics.CourseName; - HideInLearnerPortal = courseStatistics.HideInLearnerPortal; CategoryName = courseStatistics.CategoryName; LearningMinutes = courseStatistics.LearningMinutes; Tags = FilterableTagHelper.GetCurrentTagsForCourseStatistics(courseStatistics); } public int CustomisationId { get; set; } - public int CentreId { get; set; } - public bool Active { get; set; } public int DelegateCount { get; set; } - public int CompletedCount { get; set; } public int InProgressCount { get; set; } public string CourseName { get; set; } - public double PassRate { get; set; } - public bool HideInLearnerPortal { get; set; } public string CategoryName { get; set; } public string LearningMinutes { get; set; } public string GenerateEmailHref => $"mailto:?subject={GenerateEmailSubject}&body={GenerateEmailContent}"; From dc83f8cfcdaf298cf72a2d19f29bdd9d45571208 Mon Sep 17 00:00:00 2001 From: Daniel Bloxham Date: Fri, 16 Jul 2021 14:20:47 +0100 Subject: [PATCH 3/6] HEEDLS-431 - Prevent Copy Course Link from having visited styling --- .../Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml index 56bcfc4502..831223e6af 100644 --- a/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml @@ -60,7 +60,7 @@
- Copy course link + Copy course link

To share this course with others, click Launch Course and copy the URL to the clipboard.

From ef08a8c33eea0f4a59230a4ca1bd5f757271aa81 Mon Sep 17 00:00:00 2001 From: Daniel Bloxham Date: Tue, 20 Jul 2021 10:46:09 +0100 Subject: [PATCH 4/6] HEEDLS-431 - Review markups --- .../FilterOptions/CourseFilterOptions.cs | 13 ++--- .../Helpers/FilterableTagHelper.cs | 8 +-- .../trackingSystem/centreCourseSetup.ts | 51 ++++++++++--------- .../Styles/trackingSystem/courseSetup.scss | 15 ++++++ .../SearchableCourseStatisticsViewModel.cs | 16 ++++-- .../CourseSetup/_CentreCourseCard.cshtml | 10 ++-- 6 files changed, 69 insertions(+), 44 deletions(-) diff --git a/DigitalLearningSolutions.Web/Helpers/FilterOptions/CourseFilterOptions.cs b/DigitalLearningSolutions.Web/Helpers/FilterOptions/CourseFilterOptions.cs index d3b66cd189..1e0527b352 100644 --- a/DigitalLearningSolutions.Web/Helpers/FilterOptions/CourseFilterOptions.cs +++ b/DigitalLearningSolutions.Web/Helpers/FilterOptions/CourseFilterOptions.cs @@ -4,9 +4,9 @@ using DigitalLearningSolutions.Web.Models.Enums; using DigitalLearningSolutions.Web.ViewModels.Common.SearchablePage; - public static class CourseActiveStatusFilterOptions + public static class CourseStatusFilterOptions { - private const string Group = "ActiveStatus"; + private const string Group = "Status"; public static readonly FilterOptionViewModel IsInactive = new FilterOptionViewModel( "Inactive", @@ -19,20 +19,15 @@ public static class CourseActiveStatusFilterOptions Group + FilteringHelper.Separator + nameof(CourseStatistics.Active) + FilteringHelper.Separator + "true", FilterStatus.Success ); - } - - public static class CourseHiddenInLearningPortalStatusFilterOptions - { - private const string Group = "HiddenInLearningPortalStatus"; - public static readonly FilterOptionViewModel IsHidden = new FilterOptionViewModel( + public static readonly FilterOptionViewModel IsHiddenInLearningPortal = new FilterOptionViewModel( "Hidden in Learning Portal", Group + FilteringHelper.Separator + nameof(CourseStatistics.HideInLearnerPortal) + FilteringHelper.Separator + "true", FilterStatus.Warning ); - public static readonly FilterOptionViewModel IsNotHidden = new FilterOptionViewModel( + public static readonly FilterOptionViewModel IsNotHiddenInLearningPortal = new FilterOptionViewModel( "Visible in Learning Portal", Group + FilteringHelper.Separator + nameof(CourseStatistics.HideInLearnerPortal) + FilteringHelper.Separator + "true", diff --git a/DigitalLearningSolutions.Web/Helpers/FilterableTagHelper.cs b/DigitalLearningSolutions.Web/Helpers/FilterableTagHelper.cs index 3222030fb8..cc9460eb34 100644 --- a/DigitalLearningSolutions.Web/Helpers/FilterableTagHelper.cs +++ b/DigitalLearningSolutions.Web/Helpers/FilterableTagHelper.cs @@ -62,20 +62,20 @@ CourseStatistics courseStatistics if (courseStatistics.Active) { - tags.Add(new SearchableTagViewModel(CourseActiveStatusFilterOptions.IsActive)); + tags.Add(new SearchableTagViewModel(CourseStatusFilterOptions.IsActive)); } else { - tags.Add(new SearchableTagViewModel(CourseActiveStatusFilterOptions.IsInactive)); + tags.Add(new SearchableTagViewModel(CourseStatusFilterOptions.IsInactive)); } if (courseStatistics.HideInLearnerPortal) { - tags.Add(new SearchableTagViewModel(CourseHiddenInLearningPortalStatusFilterOptions.IsHidden)); + tags.Add(new SearchableTagViewModel(CourseStatusFilterOptions.IsHiddenInLearningPortal)); } else { - tags.Add(new SearchableTagViewModel(CourseHiddenInLearningPortalStatusFilterOptions.IsNotHidden)); + tags.Add(new SearchableTagViewModel(CourseStatusFilterOptions.IsNotHiddenInLearningPortal)); } return tags; diff --git a/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts b/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts index f847873b0b..d3b47d79ca 100644 --- a/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts +++ b/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts @@ -1,42 +1,47 @@ -const copyCourseLinkClass = 'copy-course-link'; +const copyCourseLinkClass = 'copy-course-button'; const copyLinkIdPrefix = 'copy-course-'; const launchCourseButtonIdPrefix = 'launch-course-'; setupCourseLinkClipboardCopiers(); function setupCourseLinkClipboardCopiers() { - const copyCourseLinks = document.getElementsByClassName(copyCourseLinkClass); - - for (let i = 0; i < copyCourseLinks.length; i += 1) { - const currentLink = copyCourseLinks[i]; - const linkId = currentLink.id; - const customisationId = linkId.slice(copyLinkIdPrefix.length); - - currentLink.addEventListener('click', (e) => { - e.preventDefault(); - e.stopPropagation(); - copyLaunchCourseLinkToClipboard(customisationId); - }); - } + const copyCourseLinks = Array.from(document.getElementsByClassName(copyCourseLinkClass)); + + copyCourseLinks.forEach( + (currentLink) => { + const linkId = currentLink.id; + const customisationId = linkId.slice(copyLinkIdPrefix.length); + currentLink.addEventListener('click', () => { copyLaunchCourseLinkToClipboard(customisationId); }); + } + ); } function copyLaunchCourseLinkToClipboard(customisationId: string) { const launchCourseButtonId = launchCourseButtonIdPrefix + customisationId; - const copyText = document.getElementById(launchCourseButtonId) as HTMLAnchorElement; - const link = copyText.href; + const launchCourseButton = document.getElementById(launchCourseButtonId) as HTMLAnchorElement; + const link = launchCourseButton.href; const succeeded = copyTextToClipboard(link); - let alertMessage: string; + const alertMessage = succeeded + ? `Copied the text: ${link}` + : `Copy not supported or blocked. Try manually selecting and copying: ${link}`; + + alert(alertMessage); +} + +function copyTextToClipboard(textToCopy: string): boolean { + let succeeded: boolean; - if (succeeded) { - alertMessage = `Copied the text: ${link}`; - } else { - alertMessage = `Copy not supported or blocked. Try manually selecting and copying: ${link}`; + try { + navigator.clipboard.writeText(textToCopy); + succeeded = true; + } catch (e) { + succeeded = copyTextToClipboardFallback(textToCopy); } - alert(alertMessage); + return succeeded; } -function copyTextToClipboard(textToCopy: string) : boolean { +function copyTextToClipboardFallback(textToCopy: string): boolean { const hiddenInput = document.body.appendChild(document.createElement('input')); hiddenInput.value = textToCopy; hiddenInput.select(); diff --git a/DigitalLearningSolutions.Web/Styles/trackingSystem/courseSetup.scss b/DigitalLearningSolutions.Web/Styles/trackingSystem/courseSetup.scss index 9642c57edd..0745e440f5 100644 --- a/DigitalLearningSolutions.Web/Styles/trackingSystem/courseSetup.scss +++ b/DigitalLearningSolutions.Web/Styles/trackingSystem/courseSetup.scss @@ -1,3 +1,18 @@ @import "~nhsuk-frontend/packages/core/all"; @import "../shared/cardWithButtons"; @import "../shared/searchableElements/searchableElements"; + +.copy-course-button{ + background: none; + border: none; + padding: 0; + color: $nhsuk-link-color; + @extend .nhsuk-u-font-size-19; + text-decoration: underline; + + &:hover{ + color: $nhsuk-link-hover-color; + text-decoration: none; + cursor: pointer; + } +} diff --git a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs index 136ddaacb6..29e097f770 100644 --- a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/CourseSetup/SearchableCourseStatisticsViewModel.cs @@ -1,5 +1,6 @@ namespace DigitalLearningSolutions.Web.ViewModels.TrackingSystem.CourseSetup { + using System; using DigitalLearningSolutions.Data.Models.Courses; using DigitalLearningSolutions.Web.Helpers; using DigitalLearningSolutions.Web.ViewModels.Common.SearchablePage; @@ -23,11 +24,16 @@ public SearchableCourseStatisticsViewModel(CourseStatistics courseStatistics) public string CourseName { get; set; } public string CategoryName { get; set; } public string LearningMinutes { get; set; } - public string GenerateEmailHref => $"mailto:?subject={GenerateEmailSubject}&body={GenerateEmailContent}"; - private string GenerateEmailSubject => $"Digital Learning Solutions Course Link - {CourseName}"; - private string GenerateEmailContent => $"To start your {CourseName} course, click {LaunchCourseLink}"; - private string LaunchCourseLink => - $"{ConfigHelper.GetAppConfig()[ConfigHelper.AppRootPathName]}/LearningMenu/{CustomisationId}"; + public string EmailHref => GenerateEmailHref(); + + private string GenerateEmailHref() + { + var launchCourseLink = + $"{ConfigHelper.GetAppConfig()[ConfigHelper.AppRootPathName]}/LearningMenu/{CustomisationId}"; + var subject = Uri.EscapeDataString($"Digital Learning Solutions Course Link - {CourseName}"); + var content = Uri.EscapeDataString($"To start your {CourseName} course, go to {launchCourseLink}"); + return $"mailto:?subject={subject}&body={content}"; + } } } diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml index 831223e6af..13881ac80a 100644 --- a/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml @@ -54,13 +54,17 @@

Want to share the course?

- Generate email + Generate email
-
+
- Copy course link +

To share this course with others, click Launch Course and copy the URL to the clipboard.

From 72ec37d3cef018bd1f6a267777b7e9d516f8d4f9 Mon Sep 17 00:00:00 2001 From: Daniel Bloxham Date: Tue, 20 Jul 2021 10:53:19 +0100 Subject: [PATCH 5/6] HEEDLS-431 - fix lint test --- .../Scripts/trackingSystem/centreCourseSetup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts b/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts index d3b47d79ca..abe985d263 100644 --- a/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts +++ b/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts @@ -12,7 +12,7 @@ function setupCourseLinkClipboardCopiers() { const linkId = currentLink.id; const customisationId = linkId.slice(copyLinkIdPrefix.length); currentLink.addEventListener('click', () => { copyLaunchCourseLinkToClipboard(customisationId); }); - } + }, ); } From 5ce276e5d0d40342b41d8bbaca22a1d2c7ed37f3 Mon Sep 17 00:00:00 2001 From: Daniel Bloxham Date: Thu, 22 Jul 2021 13:53:02 +0100 Subject: [PATCH 6/6] HEEDLS-431 - neaten up JS and centre course card --- .../trackingSystem/centreCourseSetup.ts | 14 ++++------- .../CourseSetup/_CentreCourseCard.cshtml | 25 ++++++------------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts b/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts index abe985d263..46f74db022 100644 --- a/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts +++ b/DigitalLearningSolutions.Web/Scripts/trackingSystem/centreCourseSetup.ts @@ -2,16 +2,16 @@ const copyCourseLinkClass = 'copy-course-button'; const copyLinkIdPrefix = 'copy-course-'; const launchCourseButtonIdPrefix = 'launch-course-'; -setupCourseLinkClipboardCopiers(); +setUpCourseLinkClipboardCopiers(); -function setupCourseLinkClipboardCopiers() { +function setUpCourseLinkClipboardCopiers() { const copyCourseLinks = Array.from(document.getElementsByClassName(copyCourseLinkClass)); copyCourseLinks.forEach( (currentLink) => { const linkId = currentLink.id; const customisationId = linkId.slice(copyLinkIdPrefix.length); - currentLink.addEventListener('click', () => { copyLaunchCourseLinkToClipboard(customisationId); }); + currentLink.addEventListener('click', () => copyLaunchCourseLinkToClipboard(customisationId)); }, ); } @@ -29,16 +29,12 @@ function copyLaunchCourseLinkToClipboard(customisationId: string) { } function copyTextToClipboard(textToCopy: string): boolean { - let succeeded: boolean; - try { navigator.clipboard.writeText(textToCopy); - succeeded = true; + return true; } catch (e) { - succeeded = copyTextToClipboardFallback(textToCopy); + return copyTextToClipboardFallback(textToCopy); } - - return succeeded; } function copyTextToClipboardFallback(textToCopy: string): boolean { diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml index 13881ac80a..b74f5ccaf9 100644 --- a/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/CourseSetup/_CentreCourseCard.cshtml @@ -51,23 +51,14 @@ -
-
-

Want to share the course?

- Generate email -
-
- -
-
- -

To share this course with others, click Launch Course and copy the URL to the clipboard.

-
-
+

Want to share the course?

+ Generate email + +

To share this course with others, click Launch Course and copy the URL to the clipboard.