From fcff0032a681acb1cba1f741956b361a0d403ece Mon Sep 17 00:00:00 2001 From: Arunima George Date: Fri, 1 Aug 2025 15:08:29 +0100 Subject: [PATCH 1/4] TD-5761: Draft commit --- .../LearningHub.Nhs.AdminUI.csproj | 2 +- ...rningHub.Nhs.WebUI.AutomatedUiTests.csproj | 1 + .../Controllers/MyAccountController.cs | 153 ++++++- .../Interfaces/IUserService.cs | 26 ++ .../LearningHub.Nhs.WebUI.csproj | 2 +- .../SideMenu/SideNavigationConfiguration.cs | 24 +- .../MyAccountEmploymentDetailsViewModel.cs | 95 +++++ .../MyAccountPersonalDetailsViewModel.cs | 64 +++ .../UserProfile/MyAccountSecurityViewModel.cs | 45 ++ LearningHub.Nhs.WebUI/Services/UserService.cs | 155 +++++++ .../Styles/layout/_layout.scss | 35 ++ .../Views/MyAccount/ChangeLocation.cshtml | 194 +++++++++ .../MyAccount/ChangePersonalDetails.cshtml | 110 +++++ .../Views/MyAccount/Index.cshtml | 393 ++++-------------- .../Views/MyAccount/MyAccountSecurity.cshtml | 126 ++++++ .../Views/MyAccount/MyEmployment.cshtml | 108 +++++ .../Views/MyAccount/_LeftNav.cshtml | 43 ++ .../Views/Notification/Index.cshtml | 4 +- ...gHub.Nhs.OpenApi.Services.Interface.csproj | 2 +- .../LearningHub.Nhs.OpenApi.Services.csproj | 2 +- .../LearningHub.Nhs.OpenApi.Tests.csproj | 1 + .../LearningHub.NHS.OpenAPI.csproj | 1 + .../LearningHub.Nhs.Api.csproj | 2 +- .../LearningHub.Nhs.Api.Shared.csproj | 2 +- .../LearningHub.Nhs.Api.UnitTests.csproj | 2 +- ...earningHub.Nhs.Repository.Interface.csproj | 2 +- .../LearningHub.Nhs.Repository.csproj | 2 +- .../LearningHub.Nhs.Services.Interface.csproj | 2 +- .../LearningHub.Nhs.Services.UnitTests.csproj | 2 +- .../LearningHub.Nhs.Services.csproj | 2 +- ...earningHub.Nhs.Migration.ConsoleApp.csproj | 2 +- ...LearningHub.Nhs.Migration.Interface.csproj | 2 +- .../LearningHub.Nhs.Migration.Models.csproj | 2 +- ...ub.Nhs.Migration.Staging.Repository.csproj | 2 +- ...LearningHub.Nhs.Migration.UnitTests.csproj | 2 +- .../LearningHub.Nhs.Migration.csproj | 2 +- 36 files changed, 1269 insertions(+), 345 deletions(-) create mode 100644 LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountEmploymentDetailsViewModel.cs create mode 100644 LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs create mode 100644 LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountSecurityViewModel.cs create mode 100644 LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLocation.cshtml create mode 100644 LearningHub.Nhs.WebUI/Views/MyAccount/ChangePersonalDetails.cshtml create mode 100644 LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountSecurity.cshtml create mode 100644 LearningHub.Nhs.WebUI/Views/MyAccount/MyEmployment.cshtml create mode 100644 LearningHub.Nhs.WebUI/Views/MyAccount/_LeftNav.cshtml diff --git a/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj b/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj index a0de54f8f..019a073ab 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj +++ b/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj @@ -83,7 +83,7 @@ - + diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj b/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj index 1569f9734..ed0aaa413 100644 --- a/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj @@ -11,6 +11,7 @@ + diff --git a/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs b/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs index d1dadb902..61c119f2a 100644 --- a/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs @@ -131,8 +131,91 @@ public async Task Index(string returnUrl = null, bool? checkDetai } } + var userPersonalDetails = await this.userService.GetMyAccountPersonalDetailsAsync(); + ////var userProfileSummary = await this.userService.GetUserProfileSummaryAsync(); + ////var userProfileSummary1 = await this.userService.GetCurrentUserBasicDetailsAsync(); + return this.View("Index", userPersonalDetails); + } + + /// + /// MyEmploymentDetails. + /// + /// IActionResult. + [HttpGet] + [Route("myaccount-employement")] + public async Task MyEmploymentDetails() + { + var employmentDetails = await this.userService.GetMyEmploymentDetailsAsync(); + return this.View("MyEmployment", employmentDetails); + } + + /// + /// User profile actions. + /// + /// The redirect back url. + /// Whether to check account details. + /// IActionResult. + [HttpGet] + [Route("myaccount-security")] + public async Task MyAccountSecurity(string returnUrl = null, bool? checkDetails = false) + { + var securityDetails = await this.userService.GetMyAccountSecurityDetailsAsync(); + return this.View("MyAccountSecurity", securityDetails); + } + + /// + /// ChangePersonalDetails. + /// + /// ActionResult. + [HttpGet] + [Route("myaccount/ChangePersonalDetails")] + public async Task ChangePersonalDetails() + { + var userPersonalDetails = await this.userService.GetMyAccountPersonalDetailsAsync(); + return this.View("ChangePersonalDetails", userPersonalDetails); + } + + /// + /// To Update first name. + /// + /// model. + /// ActionResult. + [HttpPost] + public async Task UpdatePersonalDetails(MyAccountPersonalDetailsViewModel model) + { + if (!this.ModelState.IsValid) + { + return this.View("ChangePersonalDetails", model); + } + + await this.userService.UpdateMyAccountPersonalDetailsAsync(this.CurrentUserId, model); + await this.MyAccountUpdatePrimaryEmail(model.PrimaryEmailAddress); + this.ViewBag.SuccessMessage = "Success"; + return this.View("SuccessMessage"); + } + + /// + /// ChangeLocation. + /// + /// country id. + /// ActionResult. + [HttpGet] + [Route("myaccount/ChangeLocation")] + public async Task ChangeLocation(int? selectedCountryId) + { + this.TempData.Clear(); + var userLocationViewModel = await this.userService.GetUserLocationDetailsAsync(); var userProfileSummary = await this.userService.GetUserProfileSummaryAsync(); - return this.View("Index", userProfileSummary); + if (selectedCountryId.HasValue) + { + userLocationViewModel.SelectedCountryId = selectedCountryId; + } + + await this.multiPageFormService.SetMultiPageFormData( + userLocationViewModel, + MultiPageFormDataFeature.AddRegistrationPrompt, + this.TempData); + return this.View("ChangeLocation", new Tuple(userProfileSummary, userLocationViewModel)); } /// @@ -827,8 +910,10 @@ await this.userService.UpdateUserEmployment( LocationId = profile.LocationId, }); - this.ViewBag.SuccessMessage = "Your job details have been changed"; - return this.View("SuccessMessage"); + ////this.ViewBag.SuccessMessage = "Your job details have been changed"; + ////return this.View("SuccessMessage"); + + return this.RedirectToAction(nameof(this.ChangePrimarySpecialty), new UserPrimarySpecialtyUpdateViewModel { }); } else { @@ -887,8 +972,10 @@ await this.userService.UpdateUserEmployment( LocationId = profile.LocationId, }); - this.ViewBag.SuccessMessage = "Your primary specialty has been changed"; - return this.View("SuccessMessage"); + ////this.ViewBag.SuccessMessage = "Your primary specialty has been changed"; + ////return this.View("SuccessMessage"); + + return this.RedirectToAction(nameof(this.ChangeStartDate), new UserStartDateUpdateViewModel { }); } else { @@ -940,8 +1027,10 @@ await this.userService.UpdateUserEmployment( LocationId = profile.LocationId, }); - this.ViewBag.SuccessMessage = "Your job start date has been changed"; - return this.View("SuccessMessage"); + ////this.ViewBag.SuccessMessage = "Your job start date has been changed"; + ////return this.View("SuccessMessage"); + + return this.RedirectToAction(nameof(this.ChangeWorkPlace), new UserWorkPlaceUpdateViewModel { }); } } else @@ -1012,7 +1101,7 @@ await this.userService.UpdateUserEmployment( await this.cacheService.SetAsync(this.LoginWizardCacheKey, Newtonsoft.Json.JsonConvert.SerializeObject(loginWizardViewModel)); } - this.ViewBag.SuccessMessage = "Your place of work has been changed"; + this.ViewBag.SuccessMessage = "Your employment details have been updated"; return this.View("SuccessMessage"); } @@ -1197,5 +1286,53 @@ public async Task CancelEmailChangeValidationToken() this.ViewBag.SuccessMessage = CommonValidationErrorMessages.EmailCancelMessage; return this.View("SuccessMessage"); } + + private async Task MyAccountUpdatePrimaryEmail(string primaryEmailAddress) + { + bool userPrimaryEmailAddressChanged = false; + var user = await this.userService.GetUserByUserIdAsync(this.CurrentUserId); + if (user != null) + { + if (!string.IsNullOrEmpty(primaryEmailAddress) && user.EmailAddress.ToLower() != primaryEmailAddress.ToLower()) + { + userPrimaryEmailAddressChanged = true; + } + } + + if (userPrimaryEmailAddressChanged) + { + if (await this.userService.DoesEmailAlreadyExist(primaryEmailAddress)) + { + this.ModelState.AddModelError( + nameof(primaryEmailAddress), + CommonValidationErrorMessages.DuplicateEmailAddress); + ////return this.View("ChangePrimaryEmail", primaryEmailAddress); + } + else + { + var isUserRoleUpgrade = await this.userService.ValidateUserRoleUpgradeAsync(user.EmailAddress, primaryEmailAddress); + UserRoleUpgrade userRoleUpgradeModel = new UserRoleUpgrade() + { + UserId = this.CurrentUserId, + EmailAddress = primaryEmailAddress, + }; + if (isUserRoleUpgrade) + { + userRoleUpgradeModel.UserHistoryTypeId = (int)UserHistoryType.UserRoleUpgarde; + } + else + { + userRoleUpgradeModel.UserHistoryTypeId = (int)UserHistoryType.UserDetails; + } + + await this.userService.GenerateEmailChangeValidationTokenAndSendEmailAsync(primaryEmailAddress, isUserRoleUpgrade); + await this.userService.UpdateUserRoleUpgradeAsync(); + await this.userService.CreateUserRoleUpgradeAsync(userRoleUpgradeModel); + ////this.ViewBag.SuccessMessage = CommonValidationErrorMessages.EmailChangeRequestedSucessMessage; + ////this.ViewBag.Status = "Valid"; + ////return this.View("ConfirmEmailSuccessMessage"); + } + } + } } } \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs b/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs index 19ee0a927..320dcb9c3 100644 --- a/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs +++ b/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs @@ -478,5 +478,31 @@ public interface IUserService /// the string. /// base64 string. string Base64MD5HashDigest(string szString); + + /// + /// The get current user profile for My account. + /// + /// The . + Task GetMyAccountPersonalDetailsAsync(); + + /// + /// Update MyAccount Personal Details Async. + /// + /// userId. + /// MyAccountPersonalDetailsViewModel. + /// The . + Task UpdateMyAccountPersonalDetailsAsync(int userId, MyAccountPersonalDetailsViewModel model); + + /// + /// Get MyEmployment Details Async. + /// + /// The . + Task GetMyEmploymentDetailsAsync(); + + /// + /// Get MyAccount Security Details Async. + /// + /// The . + Task GetMyAccountSecurityDetailsAsync(); } } diff --git a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj index dc2cf661d..9ff630819 100644 --- a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj +++ b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj @@ -107,7 +107,7 @@ - + diff --git a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs index 9f95fc173..4889d7fb8 100644 --- a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs +++ b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs @@ -26,30 +26,30 @@ public static IEnumerable GetGroupedMenus() new SideNavigationItem { Text = "Personal details", - Controller = "Account", - Action = "PersonalDetails", - IsActive = route => MatchRoute(route, "Account", "PersonalDetails"), + Controller = "MyAccount", + Action = "Index", + IsActive = route => MatchRoute(route, "MyAccount", "PersonalDetails"), }, new SideNavigationItem { Text = "My employment", - Controller = "Account", - Action = "MyEmployment", - IsActive = route => MatchRoute(route, "Account", "MyEmployment"), + Controller = "MyAccount", + Action = "MyEmploymentDetails", + IsActive = route => MatchRoute(route, "MyAccount", "MyEmploymentDetails"), }, new SideNavigationItem { Text = "Security", - Controller = "Account", - Action = "Security", - IsActive = route => MatchRoute(route, "Account", "Security"), + Controller = "MyAccount", + Action = "MyAccountSecurity", + IsActive = route => MatchRoute(route, "MyAccount", "MyAccountSecurity"), }, new SideNavigationItem { Text = "Notification", - Controller = "Account", - Action = "Notification", - IsActive = route => MatchRoute(route, "Account", "Notification"), + Controller = "Notification", + Action = "Index", + IsActive = route => MatchRoute(route, "Notification", "Index"), }, }, }, diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountEmploymentDetailsViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountEmploymentDetailsViewModel.cs new file mode 100644 index 000000000..41b93b692 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountEmploymentDetailsViewModel.cs @@ -0,0 +1,95 @@ +namespace LearningHub.Nhs.WebUI.Models.UserProfile +{ + using System; + + /// + /// Defines the . + /// + public class MyAccountEmploymentDetailsViewModel + { + /// + /// Gets or sets the Id. + /// + public int Id { get; set; } + + /// + /// Gets or sets the Country. + /// + public string Country { get; set; } + + /// + /// Gets or sets the Region. + /// + public string Region { get; set; } + + /// + /// Gets or sets the CountryName. + /// + public string CountryName { get; set; } + + /// + /// Gets or sets the RegionName. + /// + public string RegionName { get; set; } + + /// + /// Gets or sets the user employment id. + /// + public int EmploymentId { get; set; } + + /// + /// Gets or sets the job role id. + /// + public int? JobRoleId { get; set; } + + /// + /// Gets or sets the CurrentRole. + /// + public string JobRole { get; set; } + + /// + /// Gets or sets the medical council id. + /// + public int? MedicalCouncilId { get; set; } + + /// + /// Gets or sets the ProfessionalRegistrationNumber. + /// + public string MedicalCouncilNo { get; set; } + + /// + /// Gets or sets the grade id. + /// + public int? GradeId { get; set; } + + /// + /// Gets or sets the Grade. + /// + public string Grade { get; set; } + + /// + /// Gets or sets the specialty id. + /// + public int? SpecialtyId { get; set; } + + /// + /// Gets or sets the PrimarySpecialty. + /// + public string PrimarySpecialty { get; set; } + + /// + /// Gets or sets the StartDate. + /// + public DateTimeOffset? JobStartDate { get; set; } + + /// + /// Gets or sets the location id. + /// + public int LocationId { get; set; } + + /// + /// Gets or sets the PlaceOfWork. + /// + public string PlaceOfWork { get; set; } + } +} diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs new file mode 100644 index 000000000..05abe5e71 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs @@ -0,0 +1,64 @@ +namespace LearningHub.Nhs.WebUI.Models.UserProfile +{ + using System.ComponentModel; + using System.ComponentModel.DataAnnotations; + using LearningHub.Nhs.WebUI.Attributes; + using LearningHub.Nhs.WebUI.Helpers; + + /// + /// Defines the . + /// + public class MyAccountPersonalDetailsViewModel + { + /// + /// Gets or sets the UserName. + /// + [DisplayName("Username")] + public string UserName { get; set; } + + /// + /// Gets or sets the Name. + /// + [DisplayName("Name")] + public string Name { get; set; } + + /// + /// Gets or sets the FirstName. + /// + [Required(ErrorMessage = "Enter a first name")] + [StringLength(50, MinimumLength = 1, ErrorMessage = "First name must be less than 50 characters.")] + [DisplayName("First name")] + public string FirstName { get; set; } + + /// + /// Gets or sets the LastName. + /// + [Required(ErrorMessage = "Enter a last name")] + [StringLength(50, MinimumLength = 1, ErrorMessage = "Last name must be less than 50 characters.")] + [DisplayName("Last name")] + public string LastName { get; set; } + + /// + /// Gets or sets the PreferredName. + /// + [StringLength(50, MinimumLength = 0, ErrorMessage = "Preferred name must be less than 50 characters.")] + [DisplayName("Preferred name")] + public string PreferredName { get; set; } + + /// + /// Gets or sets the Primary Email Address. + /// + [DataType(DataType.EmailAddress)] + [Required(ErrorMessage = "Enter a primary email address")] + [MaxLength(100, ErrorMessage = CommonValidationErrorMessages.TooLongEmail)] + [EmailAddress(ErrorMessage = CommonValidationErrorMessages.InvalidEmail)] + [NoWhitespace(ErrorMessage = CommonValidationErrorMessages.WhitespaceInEmail)] + [DisplayName("Primary email address")] + public string PrimaryEmailAddress { get; set; } + + /// + /// Gets or sets the new primary email address. + /// + public string NewPrimaryEmailAddress { get; set; } + } +} diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountSecurityViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountSecurityViewModel.cs new file mode 100644 index 000000000..c27467f71 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountSecurityViewModel.cs @@ -0,0 +1,45 @@ +namespace LearningHub.Nhs.WebUI.Models.UserProfile +{ + using System; + + /// + /// Defines the . + /// + public class MyAccountSecurityViewModel + { + /// + /// Gets or sets the Id. + /// + public int Id { get; set; } + + /// + /// Gets or sets the SecondaryEmailAddress. + /// + public string SecondaryEmailAddress { get; set; } + + /// + /// Gets or sets the SecurityFirstQuestion. + /// + public string SecurityFirstQuestion { get; set; } + + /// + /// Gets or sets the SecuritySecondQuestion. + /// + public string SecuritySecondQuestion { get; set; } + + /// + /// Gets or sets the LastUpdated. + /// + public DateTimeOffset LastUpdated { get; set; } + + /// + /// Gets or sets the PasswordHash. + /// + public string PasswordHash { get; set; } + + /// + /// Gets or sets the SecurityQuestionLastUpdated. + /// + public DateTimeOffset? SecurityQuestionLastUpdated { get; set; } + } +} diff --git a/LearningHub.Nhs.WebUI/Services/UserService.cs b/LearningHub.Nhs.WebUI/Services/UserService.cs index 04a2bf68f..6978f4d38 100644 --- a/LearningHub.Nhs.WebUI/Services/UserService.cs +++ b/LearningHub.Nhs.WebUI/Services/UserService.cs @@ -1901,5 +1901,160 @@ public string Base64MD5HashDigest(string szString) return Convert.ToBase64String(abHashDigest); } + + /// + /// Get Personal details of current user for My Account. + /// + /// UserPersonalDetailsViewModel. + public async Task GetMyAccountPersonalDetailsAsync() + { + MyAccountPersonalDetailsViewModel viewModel = null; + + PersonalDetailsViewModel personalDetailsModel = await this.GetCurrentUserPersonalDetailsAsync(); + + if (personalDetailsModel != null) + { + viewModel = new MyAccountPersonalDetailsViewModel + { + UserName = personalDetailsModel.UserName, + FirstName = personalDetailsModel.FirstName, + LastName = personalDetailsModel.LastName, + PreferredName = personalDetailsModel.PreferredName, + Name = personalDetailsModel.FirstName + " " + personalDetailsModel.LastName, + PrimaryEmailAddress = personalDetailsModel.PrimaryEmailAddress, + NewPrimaryEmailAddress = personalDetailsModel.NewPrimaryEmailAddress, + }; + } + + return viewModel; + } + + /// + /// Update MyAccount Personal Details Async. + /// + /// userId. + /// personal details. + /// The . + public async Task UpdateMyAccountPersonalDetailsAsync(int userId, MyAccountPersonalDetailsViewModel model) + { + PersonalDetailsViewModel personalDetailsViewModel = new PersonalDetailsViewModel + { + UserId = userId, + FirstName = model.FirstName, + LastName = model.LastName, + PreferredName = model.PreferredName, + }; + + var json = JsonConvert.SerializeObject(personalDetailsViewModel); + var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); + + var client = await this.userApiHttpClient.GetClientAsync(); + var request = $"ElfhUser/UpdateMyAccountPersonalDetails"; + var response = await client.PutAsync(request, stringContent).ConfigureAwait(false); + + if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden) + { + throw new Exception("AccessDenied"); + } + + if (!response.IsSuccessStatusCode) + { + throw new Exception("Update personal details failed!"); + } + } + + /// + /// Get MyEmployment Details Async. + /// + /// The . + public async Task GetMyEmploymentDetailsAsync() + { + MyAccountEmploymentDetailsViewModel viewModel = null; + + var personalDetailsModel = await this.GetCurrentUserPersonalDetailsAsync(); + var employmentViewModel = await this.GetPrimaryUserEmploymentForUser(personalDetailsModel.UserId); + + if (personalDetailsModel != null) + { + viewModel = new MyAccountEmploymentDetailsViewModel + { + Id = personalDetailsModel.UserId, + + EmploymentId = employmentViewModel.Id, + JobRoleId = employmentViewModel.JobRoleId, + MedicalCouncilId = employmentViewModel.MedicalCouncilId, + MedicalCouncilNo = employmentViewModel.MedicalCouncilNo, + GradeId = employmentViewModel.GradeId, + SpecialtyId = employmentViewModel.SpecialtyId, + JobStartDate = employmentViewModel.StartDate, + LocationId = employmentViewModel.LocationId, + }; + + if (personalDetailsModel.CountryId.HasValue) + { + var country = await this.countryService.GetByIdAsync(personalDetailsModel.CountryId.Value); + viewModel.CountryName = country.Name; + } + + if (personalDetailsModel.RegionId.HasValue) + { + var region = await this.regionService.GetByIdAsync(personalDetailsModel.RegionId.Value); + viewModel.RegionName = region.Name; + } + + if (employmentViewModel.JobRoleId.HasValue) + { + var job = await this.jobRoleService.GetByIdAsync(employmentViewModel.JobRoleId.Value); + viewModel.JobRole = job.Name; + + if (employmentViewModel.GradeId.HasValue) + { + var grades = await this.gradeService.GetGradesForJobRoleAsync(employmentViewModel.JobRoleId.Value); + var grade = grades.SingleOrDefault(g => g.Id == employmentViewModel.GradeId.Value); + viewModel.Grade = grade?.Name; + } + } + + if (employmentViewModel.SpecialtyId.HasValue) + { + var specialities = await this.specialtyService.GetSpecialtiesAsync(); + var specialty = specialities.Single(s => s.Id == employmentViewModel.SpecialtyId.Value); + viewModel.PrimarySpecialty = specialty.Name; + } + + var location = await this.locationService.GetByIdAsync(employmentViewModel.LocationId); + viewModel.PlaceOfWork = $"{location.Name}
Address: {location.Address}
Org Code: {location.NhsCode}"; + } + + return viewModel; + } + + /// + /// Get MyAccount Security Details Async. + /// + /// The . + public async Task GetMyAccountSecurityDetailsAsync() + { + MyAccountSecurityViewModel viewModel = null; + + var personalDetailsModel = await this.GetCurrentUserPersonalDetailsAsync(); + var securityQuestionsViewModel = await this.loginWizardService.GetSecurityQuestionsModel(personalDetailsModel.UserId); + + if (personalDetailsModel != null) + { + viewModel = new MyAccountSecurityViewModel + { + Id = personalDetailsModel.UserId, + SecondaryEmailAddress = personalDetailsModel.SecondaryEmailAddress, + SecurityFirstQuestion = securityQuestionsViewModel.UserSecurityQuestions.Any() ? securityQuestionsViewModel.UserSecurityQuestions.First().QuestionText : null, + SecuritySecondQuestion = (securityQuestionsViewModel.UserSecurityQuestions.Any() && securityQuestionsViewModel.UserSecurityQuestions.Count > 1) ? securityQuestionsViewModel.UserSecurityQuestions[1].QuestionText : null, + LastUpdated = personalDetailsModel.LastUpdated, + PasswordHash = personalDetailsModel.PasswordHash, + SecurityQuestionLastUpdated = securityQuestionsViewModel.UserSecurityQuestions.Any() ? securityQuestionsViewModel.UserSecurityQuestions.OrderByDescending(s => s.AmendDate).Max(s => (DateTimeOffset?)s.AmendDate) : null, + }; + } + + return viewModel; + } } } diff --git a/LearningHub.Nhs.WebUI/Styles/layout/_layout.scss b/LearningHub.Nhs.WebUI/Styles/layout/_layout.scss index bbacdc52d..f0e6df0ae 100644 --- a/LearningHub.Nhs.WebUI/Styles/layout/_layout.scss +++ b/LearningHub.Nhs.WebUI/Styles/layout/_layout.scss @@ -368,3 +368,38 @@ input:required:invalid, input:focus:invalid { i { color: #4C6272; } + +.my_account_section { + align-items: flex-start; + display: inline-flex; + justify-content: flex-start; + display: inline-flex; + gap: 32px; + padding-top: 48px; + padding-bottom: 48px; +} + +/*.my-account-page-banner { + width: 100%; + height: 208px; + background-color: $nhsuk-blue; +} + +.my-account-home-link { + color: $nhsuk-white; + font-size: 16px; + font-family: Frutiger LT Std; + font-weight: 400; + text-decoration: underline; + line-height: 24px; + word-wrap: break-word +} + +.my-account-page-heading { + color: $nhsuk-white; + font-size: 48px; + font-family: Frutiger LT Std; + font-weight: 700; + line-height: 56px; + word-wrap: break-word; +}*/ diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLocation.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLocation.cshtml new file mode 100644 index 000000000..431f23fce --- /dev/null +++ b/LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLocation.cshtml @@ -0,0 +1,194 @@ +@using LearningHub.Nhs.WebUI.Models.UserProfile +@model Tuple +@{ + ViewData["DisableValidation"] = true; + ViewData["Title"] = "My Account - Change country"; + var errorHasOccurred = !ViewData.ModelState.IsValid; + const string professionalRegConditionalId = "professional-reg-conditional-Id"; + var optionYesSelected = true; +} +
+
+ +
+
+
+ Change country +
+ @if (Model.Item2.FilterText == null) + { +

Update your country

+ } + @if (Model.Item2.FilterText == null) + { +
+
+

+ +

+
+ @Model.Item1.CountryName +
+
+
+
+
+
+ } + else + { +

Search results for @Model.Item2.FilterText

+ } + +
+
+ @if (Model.Item2.FilterText == null || Model.Item2.Country.Count() == 0) + { +

Search for example, England

+ } +
+ + + +
+
+
+
+ @if (Model.Item2.Country != null && Model.Item2.Country.Count() > 0) + { +
+
+
+
+ +

+ Select your country +

+
+
+ @foreach (var countries in Model.Item2.Country) + { +
+ + + + +
+ } +
+ +
+
+
+
+
+ +
+ } + else + { + if (Model.Item2.FilterText != null || @errorHasOccurred) + { + @await Html.PartialAsync("SerachNoResults", Model.Item2.FilterText) + } + } +
+ +
+ +
+ +

+ How would you prefer to be contacted? +

+
+
+ Select one option +
+
+
+ + +
+
+
+ +
+ +
+
+ + +
+
+
+ +
+ +
+
+ + +
+
+
+ +
+ +
+
+
+
+ + +
+ + +
+
+ +
+
+
+
+
\ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/ChangePersonalDetails.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/ChangePersonalDetails.cshtml new file mode 100644 index 000000000..b9622ce3e --- /dev/null +++ b/LearningHub.Nhs.WebUI/Views/MyAccount/ChangePersonalDetails.cshtml @@ -0,0 +1,110 @@ +@model LearningHub.Nhs.WebUI.Models.UserProfile.MyAccountPersonalDetailsViewModel + +@{ + ViewData["DisableValidation"] = true; + ViewData["Title"] = "My Account - Change first name"; + var errorHasOccurred = !ViewData.ModelState.IsValid; +} +
+
+ +
+
+
+ @if (errorHasOccurred) + { + + } +
+

Update personal details

+ @*
+ First name +
*@ + + @*

first name

*@ +
+ + @* + *@ +
+
+ +
+ @*
+ Change last name +
+

Update your last name

*@ +
+ + @* + *@ +
+
+ +
+ @*
+ Change preferred name +
+

Update your preferred name

*@ +
+ + @* + *@ +
+
+ +
+ @*
+
+

Enter your new primary email address

+
+
*@ +
+ +
+
+ +
+ +
+
+
+
+
+
\ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/Index.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/Index.cshtml index 15e78e763..ac9701963 100644 --- a/LearningHub.Nhs.WebUI/Views/MyAccount/Index.cshtml +++ b/LearningHub.Nhs.WebUI/Views/MyAccount/Index.cshtml @@ -1,336 +1,117 @@ -@model LearningHub.Nhs.WebUI.Models.UserProfile.UserProfileSummaryViewModel +@model LearningHub.Nhs.WebUI.Models.UserProfile.MyAccountPersonalDetailsViewModel @{ - ViewData["Title"] = "My account details"; + ViewData["Title"] = "Personal Details"; var isgeneralUser = User.IsInRole("BasicUser"); } -
-
-
-
-

@ViewData["Title"]

- @if (isgeneralUser) - { -
+ +
+ - - @if (this.ViewBag.CheckDetails == true) - { -
- Information: -

Please check that your details are up-to-date.

-
- } - - @if (!ViewData.ModelState.IsValid) - { - - } - -

Personal details

-
- -
-
- Username -
-
- @Model.UserName -
-
-
-
- First name -
-
- @Model.FirstName -
- -
- - Change first name - - -
- -
-
-
- Last name -
-
- @Model.LastName -
- -
- - - Change last name - - -
- -
-
-
- Preferred name -
-
- @Model.PreferredName -
- -
- - Change preferred name - - -
- -
-
- -

Location

-
- -
-
- Country -
-
- @Model.CountryName -
+
+ } -
+ @if (this.ViewBag.CheckDetails == true) + { +
+ Information: +

Please check that your details are up-to-date.

+
+ } - - Change country - + @if (!ViewData.ModelState.IsValid) + { + + } -
+ +
-
- @if (Model.CountryName == "England") - {
- Region + Username
- @Model.RegionName + @Model.UserName
- -
- - - Change region - - +
+
+
+ Name +
+
+ @Model.Name
- } - - -

Email address

-
- -
-
- Primary email address -
- @if (Model.NewPrimaryEmailAddress != "" && Model.NewPrimaryEmailAddress != null) - { -
- Email pending -
- } - else - { +
+
+ Preferred name +
- @Model.PrimaryEmailAddress + @Model.PreferredName
- } - -
- - - Change primary email - -
- -
- -
-
- Secondary email address -
-
- @Model.SecondaryEmailAddress -
- -
- - - Change secondry email - - -
- -
-
- @if (Model.NewPrimaryEmailAddress != "" && Model.NewPrimaryEmailAddress != null) - { -
-
-

- The email address @Model.NewPrimaryEmailAddress is pending validation. -
You can resend the confirmation email or cancel this email change. -

-
-
- } -

Security

-
- -
-
- Password -
-
- ************* -
- -
- - - Change password - - -
- -
- -
-
- First security question -
-
- @Model.SecurityFirstQuestion -
- -
- - - Change security question 1 - - -
- -
-
-
- Second security question -
-
- @Model.SecuritySecondQuestion -
- -
- - - Change security question 2 - - -
- -
-
+
+
+
+ Primary email address +
+ @if (Model.NewPrimaryEmailAddress != "" && Model.NewPrimaryEmailAddress != null) + { +
+ Email pending +
+ } + else + { +
+ @Model.PrimaryEmailAddress +
+ } -

Job details

-
+
-
-
Current role
-
@Model.JobRole
-
- - Change current role - -
-
+ - @if (!string.IsNullOrEmpty(Model.MedicalCouncilNo)) + @if (Model.NewPrimaryEmailAddress != "" && Model.NewPrimaryEmailAddress != null) { -
-
Professional registration number
-
@Model.MedicalCouncilNo
-
- - Change professional registration number - -
+
+
+

+ The email address @Model.NewPrimaryEmailAddress is pending validation. +
You can resend the confirmation email or cancel this email change. +

+
} - @if (!User.IsInRole("BasicUser")) - { -
-
Grade
-
@Model.Grade
-
- - Change grade - -
-
- -
-
Primary specialty
-
@Model.PrimarySpecialty
-
- - Change primary specialty - -
-
-
-
Start date
-
@Model.JobStartDate?.ToString("dd MMMM yyyy")
-
- - Change start date - -
-
+ + Update details + -
-
Place of work
-
@Html.Raw(Model.PlaceOfWork)
-
- - Change place of work - -
-
+ @if (this.ViewBag.CheckDetails == true) + { +
+ +
+ +
+
} - - - @if (this.ViewBag.CheckDetails == true) - { -
- -
- -
-
- } -
-
\ No newline at end of file +
+ +
+
\ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountSecurity.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountSecurity.cshtml new file mode 100644 index 000000000..7c9ada9ba --- /dev/null +++ b/LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountSecurity.cshtml @@ -0,0 +1,126 @@ +@model LearningHub.Nhs.WebUI.Models.UserProfile.MyAccountSecurityViewModel + +@{ + ViewData["Title"] = "Security"; +} +
+
+
+
+ @await Component.InvokeAsync("SideNav", new { groupTitle = "Account" }) +
+
+ + @if (!ViewData.ModelState.IsValid) + { + + } + +

Security

+
+ +
+
+ Secondary email address +
+
+ @Model.SecondaryEmailAddress +
+ +
+ + + Change secondry email + + +
+ +
+ +
+
+ Password +
+
+ ************* +
+ +
+ + + Change password + + +
+ +
+ +
+
+ Security questions +
+
+ Set on @Model.SecurityQuestionLastUpdated +
+ +
+ + + Change security question 2 + + +
+ +
+ + @*
+
+ First security question +
+
+ @Model.SecurityFirstQuestion +
+ +
+ + + Change security question 1 + + +
+ +
+
+
+ Second security question +
+
+ @Model.SecuritySecondQuestion +
+ +
+ + + Change security question 2 + + +
+ +
*@ +
+ + @if (this.ViewBag.CheckDetails == true) + { +
+ +
+ +
+
+ } +
+
+
+
\ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/MyEmployment.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/MyEmployment.cshtml new file mode 100644 index 000000000..7ec254a33 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Views/MyAccount/MyEmployment.cshtml @@ -0,0 +1,108 @@ +@model LearningHub.Nhs.WebUI.Models.UserProfile.MyAccountEmploymentDetailsViewModel + +@{ + ViewData["Title"] = "My employment"; + var isgeneralUser = User.IsInRole("BasicUser"); +} +
+
+
+
+ @await Component.InvokeAsync("SideNav", new { groupTitle = "Account" }) +
+
+ @if (!ViewData.ModelState.IsValid) + { + + } +

@ViewData["Title"]

+

Job details

+
+ +
+
Current role
+
@Model.JobRole
+
+ + @if (!string.IsNullOrEmpty(Model.MedicalCouncilNo)) + { +
+
Professional registration number
+
@Model.MedicalCouncilNo
+
+ } + @if (!User.IsInRole("BasicUser")) + { +
+
Grade
+
@Model.Grade
+
+ +
+
Primary specialty
+
@Model.PrimarySpecialty
+
+ +
+
Start date
+
@Model.JobStartDate?.ToString("dd MMMM yyyy")
+
+ +
+
Place of work
+
@Html.Raw(Model.PlaceOfWork)
+
+ } +
+ + + Update details + + +

Location

+ + +
+ +
+
+ Country +
+
+ @Model.CountryName +
+ +
+ @if (Model.CountryName == "England") + { +
+
+ Region +
+
+ @Model.RegionName +
+ +
+ } +
+ + + Update location + + + @if (this.ViewBag.CheckDetails == true) + { +
+ +
+ +
+
+ } +
+
+
+
\ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/_LeftNav.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/_LeftNav.cshtml new file mode 100644 index 000000000..40cb9bb3d --- /dev/null +++ b/LearningHub.Nhs.WebUI/Views/MyAccount/_LeftNav.cshtml @@ -0,0 +1,43 @@ + +@{ +} + +@section Styles { + +} + +@* *@ + +@await Component.InvokeAsync("SideNav", new { groupTitle = "Account" }) diff --git a/LearningHub.Nhs.WebUI/Views/Notification/Index.cshtml b/LearningHub.Nhs.WebUI/Views/Notification/Index.cshtml index 14b3369df..39f56672c 100644 --- a/LearningHub.Nhs.WebUI/Views/Notification/Index.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Notification/Index.cshtml @@ -1,7 +1,9 @@ @{ ViewData["Title"] = "System notifications"; } - +
+ @await Component.InvokeAsync("SideNav", new { groupTitle = "Account" }) +
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj index aa019e18c..91467fe3a 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj +++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj @@ -16,7 +16,7 @@ - + diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj index 9002a0237..48b28d9df 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj +++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj @@ -29,7 +29,7 @@ - + diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Tests/LearningHub.Nhs.OpenApi.Tests.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Tests/LearningHub.Nhs.OpenApi.Tests.csproj index c16540ee6..2a65ce40a 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi.Tests/LearningHub.Nhs.OpenApi.Tests.csproj +++ b/OpenAPI/LearningHub.Nhs.OpenApi.Tests/LearningHub.Nhs.OpenApi.Tests.csproj @@ -9,6 +9,7 @@ + diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj b/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj index e8ddf4415..1afc3c3a4 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj +++ b/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj @@ -17,6 +17,7 @@ + diff --git a/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj b/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj index 3b09a079f..f7bc8f3b5 100644 --- a/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj +++ b/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj @@ -26,7 +26,7 @@ - + diff --git a/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj b/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj index 1963fd724..166b3d80a 100644 --- a/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj +++ b/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj @@ -7,7 +7,7 @@ - + diff --git a/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj b/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj index e7a054e23..a5c27d2a4 100644 --- a/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj +++ b/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj @@ -8,7 +8,7 @@ - + diff --git a/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj b/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj index 7e09ec673..3b5864543 100644 --- a/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj +++ b/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj @@ -8,7 +8,7 @@ - + diff --git a/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj b/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj index 6da0f9200..7bd6a6258 100644 --- a/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj +++ b/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj @@ -7,7 +7,7 @@ - + diff --git a/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj b/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj index 024756991..697a1a16f 100644 --- a/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj +++ b/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj @@ -14,7 +14,7 @@ - + diff --git a/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj b/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj index 6b6743743..d9361f98d 100644 --- a/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj +++ b/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj @@ -9,7 +9,7 @@ - + diff --git a/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj b/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj index 44f8119cb..e3d97c205 100644 --- a/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj +++ b/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj @@ -10,7 +10,7 @@ - + diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj index 73e18184e..0b2b08dbd 100644 --- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj +++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj @@ -22,7 +22,7 @@ - + diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj index 7b945c483..3ed284972 100644 --- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj +++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj @@ -7,7 +7,7 @@ - + diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj index 189b0348e..c991d2f05 100644 --- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj +++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj @@ -7,7 +7,7 @@ - + diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj index 090dce6fc..aa7720aa0 100644 --- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj +++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj @@ -7,7 +7,7 @@ - + diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj index a9b7683f7..4aa414369 100644 --- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj +++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj @@ -8,7 +8,7 @@ - + diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj index 71195c130..e5456904f 100644 --- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj +++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj @@ -8,7 +8,7 @@ - + From 7a3409b6e519419eff5d6d76d3f56822fbe5b485 Mon Sep 17 00:00:00 2001 From: Arunima George Date: Tue, 12 Aug 2025 12:22:20 +0100 Subject: [PATCH 2/4] TD-5761: Latest changes. --- .../Controllers/MyAccountController.cs | 67 +++++- .../Helpers/SelectListHelper.cs | 24 +++ .../Interfaces/ICountryService.cs | 12 ++ .../Interfaces/IUserService.cs | 14 ++ .../UserProfile/MyAccountLocationViewModel.cs | 66 ++++++ .../Services/CountryService.cs | 56 +++++ LearningHub.Nhs.WebUI/Services/UserService.cs | 68 ++++++ .../Views/MyAccount/ChangeLocation.cshtml | 194 ------------------ .../Views/MyAccount/Index.cshtml | 180 ++++++++-------- .../MyAccount/MyAccountChangeLocation.cshtml | 113 ++++++++++ .../Views/MyAccount/MyAccountSecurity.cshtml | 145 +++++++------ .../Views/MyAccount/MyEmployment.cshtml | 180 ++++++++-------- .../Views/Notification/Index.cshtml | 35 +++- 13 files changed, 710 insertions(+), 444 deletions(-) create mode 100644 LearningHub.Nhs.WebUI/Helpers/SelectListHelper.cs create mode 100644 LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountLocationViewModel.cs delete mode 100644 LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLocation.cshtml create mode 100644 LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountChangeLocation.cshtml diff --git a/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs b/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs index 61c119f2a..428d2b133 100644 --- a/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs @@ -2,6 +2,7 @@ { using System; using System.Collections.Generic; + using System.Drawing; using System.Linq; using System.Net.Http; using System.Threading.Tasks; @@ -20,11 +21,14 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; + using Newtonsoft.Json.Linq; using NHSUKViewComponents.Web.ViewModels; + using static IdentityModel.ClaimComparer; using ChangePasswordViewModel = LearningHub.Nhs.WebUI.Models.UserProfile.ChangePasswordViewModel; using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration; @@ -197,25 +201,66 @@ public async Task UpdatePersonalDetails(MyAccountPersonalDetailsV /// /// ChangeLocation. /// - /// country id. /// ActionResult. [HttpGet] [Route("myaccount/ChangeLocation")] - public async Task ChangeLocation(int? selectedCountryId) + public async Task ChangeLocation() { this.TempData.Clear(); - var userLocationViewModel = await this.userService.GetUserLocationDetailsAsync(); - var userProfileSummary = await this.userService.GetUserProfileSummaryAsync(); - if (selectedCountryId.HasValue) + var userLocationViewModel = await this.userService.GetMyAccountLocationDetailsAsync(); + var allUKcountries = await this.countryService.GetAllUKCountries(); + var allUKnoncountries = await this.countryService.GetAllNonUKCountries(); + var regions = await this.regionService.GetAllAsync(); + + List radio = new List(); + foreach (var country in allUKcountries) { - userLocationViewModel.SelectedCountryId = selectedCountryId; + var newradio = new RadiosItemViewModel(country.Id.ToString(), country.Name, false, country.Name); + radio.Add(newradio); } - await this.multiPageFormService.SetMultiPageFormData( - userLocationViewModel, - MultiPageFormDataFeature.AddRegistrationPrompt, - this.TempData); - return this.View("ChangeLocation", new Tuple(userProfileSummary, userLocationViewModel)); + if (allUKnoncountries.Any(v => v.Id == userLocationViewModel.SelectedCountryId)) + { + ////userLocationViewModel.SelectedOtherCountry = true; + userLocationViewModel.SelectedOtherCountryId = userLocationViewModel.SelectedCountryId; + userLocationViewModel.SelectedCountryId = 0; + } + + userLocationViewModel.Country = radio; + userLocationViewModel.OtherCountryOptions = SelectListHelper.MapOptionsToSelectListItems(allUKnoncountries, userLocationViewModel.SelectedOtherCountryId); + + userLocationViewModel.RegionOptions = SelectListHelper.MapOptionsToSelectListItems(regions, userLocationViewModel.SelectedRegionId); + return this.View("MyAccountChangeLocation", userLocationViewModel); + } + + /// + /// To update location details. + /// + /// model. + /// The . + [HttpPost] + public async Task UpdateMyAccountLocationDetails(MyAccountLocationViewModel model) + { + if (this.ModelState.IsValid) + { + if (model?.SelectedCountryId == 0) + { + model.SelectedCountryId = model.SelectedOtherCountryId; + } + + if (model.SelectedCountryId != 1) + { + model.SelectedRegionId = null; + } + + await this.userService.UpdateMyAccountLocationDetailsAsync(this.CurrentUserId, model); + this.ViewBag.SuccessMessage = CommonValidationErrorMessages.CountrySuccessMessage; + return this.View("SuccessMessage"); + } + else + { + return this.View("MyAccountChangeLocation", model); + } } /// diff --git a/LearningHub.Nhs.WebUI/Helpers/SelectListHelper.cs b/LearningHub.Nhs.WebUI/Helpers/SelectListHelper.cs new file mode 100644 index 000000000..089665bfe --- /dev/null +++ b/LearningHub.Nhs.WebUI/Helpers/SelectListHelper.cs @@ -0,0 +1,24 @@ +namespace LearningHub.Nhs.WebUI.Helpers +{ + using System.Collections.Generic; + using System.Linq; + using elfhHub.Nhs.Models.Common; + using Microsoft.AspNetCore.Mvc.Rendering; + + /// + /// SelectListHelper. + /// + public static class SelectListHelper + { + /// + /// MapOptionsToSelectListItems. + /// + /// options. + /// selectedId. + /// SelectListItem. + public static IEnumerable MapOptionsToSelectListItems(IEnumerable options, int? selectedId = null) + { + return options.Select(o => new SelectListItem(o.Name, o.Id.ToString(), o.Id == selectedId)).ToList(); + } + } +} diff --git a/LearningHub.Nhs.WebUI/Interfaces/ICountryService.cs b/LearningHub.Nhs.WebUI/Interfaces/ICountryService.cs index 8b5fe7542..916159fe7 100644 --- a/LearningHub.Nhs.WebUI/Interfaces/ICountryService.cs +++ b/LearningHub.Nhs.WebUI/Interfaces/ICountryService.cs @@ -29,5 +29,17 @@ public interface ICountryService /// /// A representing the result of the asynchronous operation. Task> GetAllAsync(); + + /// + /// The GetAllUKCountries. + /// + /// A representing the result of the asynchronous operation. + Task> GetAllUKCountries(); + + /// + /// The GetAllNonUKCountries. + /// + /// A representing the result of the asynchronous operation. + Task> GetAllNonUKCountries(); } } diff --git a/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs b/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs index 320dcb9c3..4fda81d60 100644 --- a/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs +++ b/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs @@ -504,5 +504,19 @@ public interface IUserService ///
/// The . Task GetMyAccountSecurityDetailsAsync(); + + /// + /// Get MyAccount Location Details Async. + /// + /// The . + Task GetMyAccountLocationDetailsAsync(); + + /// + /// Update MyAccount Location Details Async. + /// + /// userId. + /// MyAccountLocationViewModel. + /// The . + Task UpdateMyAccountLocationDetailsAsync(int userId, MyAccountLocationViewModel model); } } diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountLocationViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountLocationViewModel.cs new file mode 100644 index 000000000..1e9a97b61 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountLocationViewModel.cs @@ -0,0 +1,66 @@ +namespace LearningHub.Nhs.WebUI.Models.UserProfile +{ + using System.Collections.Generic; + using System.ComponentModel; + using System.ComponentModel.DataAnnotations; + using elfhHub.Nhs.Models.Common; + using Microsoft.AspNetCore.Mvc.Rendering; + using NHSUKViewComponents.Web.ViewModels; + + /// + /// Defines the . + /// + public class MyAccountLocationViewModel + { + /// + /// Gets or sets the country id. + /// + [Required(ErrorMessage = "Select a country.")] + [DisplayName("Country")] + public int? SelectedCountryId { get; set; } + + /// + /// Gets or sets the region id. + /// + [Required(ErrorMessage = "Select a region.")] + [DisplayName("Region")] + public int? SelectedRegionId { get; set; } + + /// + /// Gets or sets selected country name. + /// + public string SelectedCountryName { get; set; } + + /// + /// Gets or sets selected region name. + /// + public string SelectedRegionName { get; set; } + + /// + /// Gets or sets the country id. + /// + ////[Required(ErrorMessage = "Select a country.")] + ////[DisplayName("Country")] + public int? SelectedOtherCountryId { get; set; } + + /// + /// Gets or sets a value indicating whether SelectedOtherCountry. + /// + public bool SelectedOtherCountry { get; set; } + + /// + /// Gets or sets the Country. + /// + public List Country { get; set; } + + /// + /// Gets or sets the OtherCountryOptions. + /// + public IEnumerable OtherCountryOptions { get; set; } + + /// + /// Gets or sets the RegionOptions. + /// + public IEnumerable RegionOptions { get; set; } + } +} diff --git a/LearningHub.Nhs.WebUI/Services/CountryService.cs b/LearningHub.Nhs.WebUI/Services/CountryService.cs index e1afd4b35..a09ca9eeb 100644 --- a/LearningHub.Nhs.WebUI/Services/CountryService.cs +++ b/LearningHub.Nhs.WebUI/Services/CountryService.cs @@ -118,5 +118,61 @@ public async Task> GetAllAsync() return viewmodel; } + + /// + /// Get a list of Uk Country records.. + /// + /// The . + public async Task> GetAllUKCountries() + { + List viewmodel = null; + + var client = await this.userApiHttpClient.GetClientAsync(); + + var request = $"Country/GetAllUKCountries"; + var response = await client.GetAsync(request).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var result = response.Content.ReadAsStringAsync().Result; + viewmodel = JsonConvert.DeserializeObject>(result); + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("AccessDenied"); + } + + return viewmodel; + } + + /// + /// Get a list of non Uk Country records. + /// + /// The . + public async Task> GetAllNonUKCountries() + { + List viewmodel = null; + + var client = await this.userApiHttpClient.GetClientAsync(); + + var request = $"Country/GetAllNonUKCountries"; + var response = await client.GetAsync(request).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var result = response.Content.ReadAsStringAsync().Result; + viewmodel = JsonConvert.DeserializeObject>(result); + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("AccessDenied"); + } + + return viewmodel; + } } } diff --git a/LearningHub.Nhs.WebUI/Services/UserService.cs b/LearningHub.Nhs.WebUI/Services/UserService.cs index 6978f4d38..eb761fe9c 100644 --- a/LearningHub.Nhs.WebUI/Services/UserService.cs +++ b/LearningHub.Nhs.WebUI/Services/UserService.cs @@ -2029,6 +2029,41 @@ public async Task GetMyEmploymentDetailsAsy return viewModel; } + /// + /// GetMyAccountLocationDetailsAsync. + /// + /// The . + public async Task GetMyAccountLocationDetailsAsync() + { + MyAccountLocationViewModel viewModel = null; + + var personalDetailsModel = await this.GetCurrentUserPersonalDetailsAsync(); + var employmentViewModel = await this.GetPrimaryUserEmploymentForUser(personalDetailsModel.UserId); + + if (personalDetailsModel != null) + { + viewModel = new MyAccountLocationViewModel + { + SelectedCountryId = personalDetailsModel.CountryId, + SelectedRegionId = personalDetailsModel.RegionId, + }; + + if (personalDetailsModel.CountryId.HasValue) + { + var country = await this.countryService.GetByIdAsync(personalDetailsModel.CountryId.Value); + viewModel.SelectedCountryName = country.Name; + } + + if (personalDetailsModel.RegionId.HasValue) + { + var region = await this.regionService.GetByIdAsync(personalDetailsModel.RegionId.Value); + viewModel.SelectedRegionName = region.Name; + } + } + + return viewModel; + } + /// /// Get MyAccount Security Details Async. /// @@ -2056,5 +2091,38 @@ public async Task GetMyAccountSecurityDetailsAsync() return viewModel; } + + /// + /// Update MyAccount Location Details Async. + /// + /// userId. + /// MyAccountLocationViewModel. + /// The . + public async Task UpdateMyAccountLocationDetailsAsync(int userId, MyAccountLocationViewModel model) + { + PersonalDetailsViewModel personalDetailsViewModel = new PersonalDetailsViewModel + { + UserId = userId, + CountryId = model.SelectedCountryId, + RegionId = model.SelectedRegionId, + }; + + var json = JsonConvert.SerializeObject(personalDetailsViewModel); + var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); + + var client = await this.userApiHttpClient.GetClientAsync(); + var request = $"ElfhUser/UpdateLocationDetails"; + var response = await client.PutAsync(request, stringContent).ConfigureAwait(false); + + if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden) + { + throw new Exception("AccessDenied"); + } + + if (!response.IsSuccessStatusCode) + { + throw new Exception("Update user location details failed!"); + } + } } } diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLocation.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLocation.cshtml deleted file mode 100644 index 431f23fce..000000000 --- a/LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLocation.cshtml +++ /dev/null @@ -1,194 +0,0 @@ -@using LearningHub.Nhs.WebUI.Models.UserProfile -@model Tuple -@{ - ViewData["DisableValidation"] = true; - ViewData["Title"] = "My Account - Change country"; - var errorHasOccurred = !ViewData.ModelState.IsValid; - const string professionalRegConditionalId = "professional-reg-conditional-Id"; - var optionYesSelected = true; -} -
-
- -
-
-
- Change country -
- @if (Model.Item2.FilterText == null) - { -

Update your country

- } - @if (Model.Item2.FilterText == null) - { -
-
-

- -

-
- @Model.Item1.CountryName -
-
-
-
-
-
- } - else - { -

Search results for @Model.Item2.FilterText

- } - -
-
- @if (Model.Item2.FilterText == null || Model.Item2.Country.Count() == 0) - { -

Search for example, England

- } -
- - - -
-
-
-
- @if (Model.Item2.Country != null && Model.Item2.Country.Count() > 0) - { -
-
-
-
- -

- Select your country -

-
-
- @foreach (var countries in Model.Item2.Country) - { -
- - - - -
- } -
- -
-
-
-
-
- -
- } - else - { - if (Model.Item2.FilterText != null || @errorHasOccurred) - { - @await Html.PartialAsync("SerachNoResults", Model.Item2.FilterText) - } - } -
- -
- -
- -

- How would you prefer to be contacted? -

-
-
- Select one option -
-
-
- - -
-
-
- -
- -
-
- - -
-
-
- -
- -
-
- - -
-
-
- -
- -
-
-
-
- - -
- - -
-
- -
-
-
-
-
\ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/Index.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/Index.cshtml index f365ed8b4..add30bab8 100644 --- a/LearningHub.Nhs.WebUI/Views/MyAccount/Index.cshtml +++ b/LearningHub.Nhs.WebUI/Views/MyAccount/Index.cshtml @@ -1,8 +1,8 @@ @model LearningHub.Nhs.WebUI.Models.UserProfile.MyAccountPersonalDetailsViewModel -@{ - ViewData["Title"] = "Personal Details"; - var isgeneralUser = User.IsInRole("BasicUser"); +@{ + ViewData["Title"] = "Personal Details"; + var isgeneralUser = User.IsInRole("BasicUser"); } @section NavBreadcrumbs { @@ -26,110 +26,110 @@
-
- @await Component.InvokeAsync("SideNav", new { groupTitle = "Account" }) -
-
+
+ @await Component.InvokeAsync("SideNav", new { groupTitle = "Account" }) +
+

@ViewData["Title"]

@if (isgeneralUser) { -
- Information: -

If you have a work email address you can upgrade to a full user account. Full users are able to access learning community resources, contribute and share knowledge and content.

-
- } - - @if (this.ViewBag.CheckDetails == true) - { -
- Information: -

Please check that your details are up-to-date.

-
- } +
+ Information: +

If you have a work email address you can upgrade to a full user account. Full users are able to access learning community resources, contribute and share knowledge and content.

+
+ } - @if (!ViewData.ModelState.IsValid) - { - - } + @if (this.ViewBag.CheckDetails == true) + { +
+ Information: +

Please check that your details are up-to-date.

+
+ } - -
+ @if (!ViewData.ModelState.IsValid) + { + + } -
-
- Username -
-
- @Model.UserName -
-
-
-
- Name -
-
- @Model.Name -
-
-
-
- Preferred name -
-
- @Model.PreferredName -
+
-
-
-
- Primary email address -
- @if (Model.NewPrimaryEmailAddress != "" && Model.NewPrimaryEmailAddress != null) - { -
- Email pending +
+
+ Username +
+
+ @Model.UserName
- } - else - { +
+
+
+ Name +
- @Model.PrimaryEmailAddress + @Model.Name
- } -
+
+
+
+ Preferred name +
+
+ @Model.PreferredName +
- +
+
+
+ Primary email address +
+ @if (Model.NewPrimaryEmailAddress != "" && Model.NewPrimaryEmailAddress != null) + { +
+ Email pending +
+ } + else + { +
+ @Model.PrimaryEmailAddress +
+ } - @if (Model.NewPrimaryEmailAddress != "" && Model.NewPrimaryEmailAddress != null) - { -
-
-

- The email address @Model.NewPrimaryEmailAddress is pending validation. -
You can resend the confirmation email or cancel this email change. -

-
- } - - Update details - + - @if (this.ViewBag.CheckDetails == true) - { -
- -
- + @if (Model.NewPrimaryEmailAddress != "" && Model.NewPrimaryEmailAddress != null) + { +
+
+

+ The email address @Model.NewPrimaryEmailAddress is pending validation. +
You can resend the confirmation email or cancel this email change. +

+
- - } -
-
+ } + + + Update details + + + @if (this.ViewBag.CheckDetails == true) + { +
+ +
+ +
+
+ } +
+
\ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountChangeLocation.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountChangeLocation.cshtml new file mode 100644 index 000000000..67e728c82 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountChangeLocation.cshtml @@ -0,0 +1,113 @@ +@model LearningHub.Nhs.WebUI.Models.UserProfile.MyAccountLocationViewModel +@{ + ViewData["DisableValidation"] = true; + ViewData["Title"] = "My Account - Location"; + var errorHasOccurred = !ViewData.ModelState.IsValid; +} +
+
+ +
+
+
+ Update location details +
+ @* @if (Model.Item2.FilterText == null) + { +

Update your country

+ } *@ + @if (Model.SelectedCountryName != null) + { +
+
+

+ +

+
+ @Model.SelectedCountryName +
+
+
+
+
+
+ } + @* else + { +

Search results for @Model.Item2.FilterText

+ } *@ +
+
+ @if (Model.Country != null && Model.Country.Any()) + { + @foreach (var country in Model.Country) + { + @if (country.Label.ToUpper() == "ENGLAND") + { +
+
+ + +
+ + +
+
+
+ } + else + { +
+ + +
+ } + + } +
+
+ + +
+ + +
+
+
+ + } +
+
+ +
+
+
+
+
+
\ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountSecurity.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountSecurity.cshtml index 7c9ada9ba..cf7e2b431 100644 --- a/LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountSecurity.cshtml +++ b/LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountSecurity.cshtml @@ -1,7 +1,26 @@ @model LearningHub.Nhs.WebUI.Models.UserProfile.MyAccountSecurityViewModel -@{ - ViewData["Title"] = "Security"; +@{ + ViewData["Title"] = "Security"; +} +@section NavBreadcrumbs { + +
+
+
+
+ +
+ Home + +
+
+

My account

+
+
+
+
+
}
@@ -11,69 +30,69 @@
- @if (!ViewData.ModelState.IsValid) - { - - } + @if (!ViewData.ModelState.IsValid) + { + + } -

Security

-
+

Security

+
-
-
- Secondary email address -
-
- @Model.SecondaryEmailAddress -
+
+
+ Secondary email address +
+
+ @Model.SecondaryEmailAddress +
-
+
- - Change secondry email - + + Change secondry email + -
+ -
+
-
-
- Password -
-
- ************* -
+
+
+ Password +
+
+ ************* +
-
+
- - Change password - + + Change password + -
+ -
+
-
-
- Security questions -
-
- Set on @Model.SecurityQuestionLastUpdated -
+
+
+ Security questions +
+
+ Set on @Model.SecurityQuestionLastUpdated +
-
+
- - Change security question 2 - + + Change security questions + -
+ -
+
- @*
+ @*
First security question
@@ -107,20 +126,20 @@
*@ -
- - @if (this.ViewBag.CheckDetails == true) - { -
- -
- -
-
- } -
-
+ + + @if (this.ViewBag.CheckDetails == true) + { +
+ +
+ +
+
+ } + + \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/MyEmployment.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/MyEmployment.cshtml index 7ec254a33..601ab4c3a 100644 --- a/LearningHub.Nhs.WebUI/Views/MyAccount/MyEmployment.cshtml +++ b/LearningHub.Nhs.WebUI/Views/MyAccount/MyEmployment.cshtml @@ -1,108 +1,126 @@ @model LearningHub.Nhs.WebUI.Models.UserProfile.MyAccountEmploymentDetailsViewModel -@{ - ViewData["Title"] = "My employment"; - var isgeneralUser = User.IsInRole("BasicUser"); +@{ + ViewData["Title"] = "My employment"; + var isgeneralUser = User.IsInRole("BasicUser"); } -
-
-
-
- @await Component.InvokeAsync("SideNav", new { groupTitle = "Account" }) -
-
- @if (!ViewData.ModelState.IsValid) - { - - } -

@ViewData["Title"]

-

Job details

-
- -
-
Current role
-
@Model.JobRole
-
+@section NavBreadcrumbs { - @if (!string.IsNullOrEmpty(Model.MedicalCouncilNo)) - { -
-
Professional registration number
-
@Model.MedicalCouncilNo
+
+
+
+
+ +
+ Home + +
+
+

My account

+
- } - @if (!User.IsInRole("BasicUser")) +
+
+
+} +@*
*@ +
+
+
+ @await Component.InvokeAsync("SideNav", new { groupTitle = "Account" }) +
+
+ @if (!ViewData.ModelState.IsValid) { -
-
Grade
-
@Model.Grade
-
+ + } +

@ViewData["Title"]

+

Job details

+
-
Primary specialty
-
@Model.PrimarySpecialty
+
Current role
+
@Model.JobRole
-
-
Start date
-
@Model.JobStartDate?.ToString("dd MMMM yyyy")
-
+ @if (!string.IsNullOrEmpty(Model.MedicalCouncilNo)) + { +
+
Professional registration number
+
@Model.MedicalCouncilNo
+
+ } + @if (!User.IsInRole("BasicUser")) + { +
+
Grade
+
@Model.Grade
+
-
-
Place of work
-
@Html.Raw(Model.PlaceOfWork)
-
- } -
+
+
Primary specialty
+
@Model.PrimarySpecialty
+
- - Update details - +
+
Start date
+
@Model.JobStartDate?.ToString("dd MMMM yyyy")
+
-

Location

+
+
Place of work
+
@Html.Raw(Model.PlaceOfWork)
+
+ } +
- -
+ + Update details + -
-
- Country -
-
- @Model.CountryName -
+

Location

+ + +
-
- @if (Model.CountryName == "England") - {
- Region + Country
- @Model.RegionName + @Model.CountryName
+ @if (Model.CountryName == "England") + { +
+
+ Region +
+
+ @Model.RegionName +
+ +
+ } +
+ + + Update location + + + @if (this.ViewBag.CheckDetails == true) + { +
+ +
+ +
+
} - - - - Update location - - - @if (this.ViewBag.CheckDetails == true) - { -
- -
- -
-
- } -
\ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Views/Notification/Index.cshtml b/LearningHub.Nhs.WebUI/Views/Notification/Index.cshtml index 39f56672c..45331215f 100644 --- a/LearningHub.Nhs.WebUI/Views/Notification/Index.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Notification/Index.cshtml @@ -1,11 +1,36 @@ @{ ViewData["Title"] = "System notifications"; } -
- @await Component.InvokeAsync("SideNav", new { groupTitle = "Account" }) -
-
- +@section NavBreadcrumbs { + +
+
+
+
+ +
+ Home + +
+
+

My account

+
+
+
+
+
+} +
+
+
+ @await Component.InvokeAsync("SideNav", new { groupTitle = "Account" }) +
+
+
+ +
+
+
@section Scripts { From 311bc2c9e1031158a8baa9c69b4624c70b7250cc Mon Sep 17 00:00:00 2001 From: Arunima George Date: Wed, 20 Aug 2025 16:26:26 +0100 Subject: [PATCH 3/4] TD-5761: merging latest changes --- .../Controllers/MyAccountController.cs | 342 ++++++++++++++---- .../Helpers/CommonValidationErrorMessages.cs | 25 ++ .../Helpers/SelectListHelper.cs | 11 + .../SideMenu/SideNavigationConfiguration.cs | 2 +- .../UserProfile/MyAccountLocationViewModel.cs | 13 +- .../MyAccountPersonalDetailsViewModel.cs | 11 + .../UserProfile/MyAccountSecurityViewModel.cs | 10 +- .../MyAcountSecurityQuestionsViewModel.cs | 54 +++ .../UserPrimarySpecialtyUpdateViewModel.cs | 15 + .../UserStartDateUpdateViewModel.cs | 10 + .../vuesrc/notification/notification.vue | 2 +- .../vuesrc/notification/notifications.vue | 6 +- LearningHub.Nhs.WebUI/Services/UserService.cs | 7 +- .../Styles/layout/_layout.scss | 10 - .../Views/MyAccount/ChangeCurrentRole.cshtml | 12 +- .../Views/MyAccount/ChangeGrade.cshtml | 4 +- .../ChangeMedicalCouncilNumber.cshtml | 2 +- .../MyAccount/ChangePersonalDetails.cshtml | 24 +- .../MyAccount/ChangePrimarySpecialty.cshtml | 31 +- .../Views/MyAccount/ChangeStartDate.cshtml | 2 +- .../Views/MyAccount/ChangeWorkPlace.cshtml | 183 +++++----- .../Views/MyAccount/Index.cshtml | 18 +- .../MyAccount/MyAccountChangeLocation.cshtml | 136 +++---- .../Views/MyAccount/MyAccountSecurity.cshtml | 63 +--- .../MyAccountSecurityQuestionsDetails.cshtml | 97 +++++ .../Views/MyAccount/MyEmployment.cshtml | 164 ++++----- .../MyAccount/SuccessMessageMyAccount.cshtml | 15 + .../Views/Notification/Index.cshtml | 6 +- 28 files changed, 866 insertions(+), 409 deletions(-) create mode 100644 LearningHub.Nhs.WebUI/Models/UserProfile/MyAcountSecurityQuestionsViewModel.cs create mode 100644 LearningHub.Nhs.WebUI/Views/MyAccount/MyAccountSecurityQuestionsDetails.cshtml create mode 100644 LearningHub.Nhs.WebUI/Views/MyAccount/SuccessMessageMyAccount.cshtml diff --git a/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs b/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs index 428d2b133..0a65cdfd2 100644 --- a/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs @@ -21,6 +21,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; @@ -136,8 +137,6 @@ public async Task Index(string returnUrl = null, bool? checkDetai } var userPersonalDetails = await this.userService.GetMyAccountPersonalDetailsAsync(); - ////var userProfileSummary = await this.userService.GetUserProfileSummaryAsync(); - ////var userProfileSummary1 = await this.userService.GetCurrentUserBasicDetailsAsync(); return this.View("Index", userPersonalDetails); } @@ -192,24 +191,33 @@ public async Task UpdatePersonalDetails(MyAccountPersonalDetailsV return this.View("ChangePersonalDetails", model); } + bool isSamePrimaryEmailPendingforValidate = await this.userService.CheckSamePrimaryemailIsPendingToValidate(model.SecondaryEmailAddress); + if (isSamePrimaryEmailPendingforValidate) + { + this.ModelState.AddModelError(string.Empty, CommonValidationErrorMessages.SecondaryEmailShouldNotBeSame); + return this.View("ChangePersonalDetails", model); + } + await this.userService.UpdateMyAccountPersonalDetailsAsync(this.CurrentUserId, model); await this.MyAccountUpdatePrimaryEmail(model.PrimaryEmailAddress); - this.ViewBag.SuccessMessage = "Success"; - return this.View("SuccessMessage"); + this.ViewBag.SuccessMessage = CommonValidationErrorMessages.PersonalDetailsSuccessMessage; + this.ViewBag.MyAction = "Index"; + return this.View("SuccessMessageMyAccount"); } /// /// ChangeLocation. /// + /// model. + /// formSubmission. /// ActionResult. [HttpGet] [Route("myaccount/ChangeLocation")] - public async Task ChangeLocation() + public async Task ChangeLocation([FromQuery] MyAccountLocationViewModel model, bool formSubmission = false) { - this.TempData.Clear(); var userLocationViewModel = await this.userService.GetMyAccountLocationDetailsAsync(); var allUKcountries = await this.countryService.GetAllUKCountries(); - var allUKnoncountries = await this.countryService.GetAllNonUKCountries(); + var allnonUKcountries = await this.countryService.GetAllNonUKCountries(); var regions = await this.regionService.GetAllAsync(); List radio = new List(); @@ -219,7 +227,7 @@ public async Task ChangeLocation() radio.Add(newradio); } - if (allUKnoncountries.Any(v => v.Id == userLocationViewModel.SelectedCountryId)) + if (allnonUKcountries.Any(v => v.Id == userLocationViewModel.SelectedCountryId)) { ////userLocationViewModel.SelectedOtherCountry = true; userLocationViewModel.SelectedOtherCountryId = userLocationViewModel.SelectedCountryId; @@ -227,39 +235,239 @@ public async Task ChangeLocation() } userLocationViewModel.Country = radio; - userLocationViewModel.OtherCountryOptions = SelectListHelper.MapOptionsToSelectListItems(allUKnoncountries, userLocationViewModel.SelectedOtherCountryId); + userLocationViewModel.OtherCountryOptions = SelectListHelper.MapOptionsToSelectListItems(allnonUKcountries, userLocationViewModel.SelectedOtherCountryId); userLocationViewModel.RegionOptions = SelectListHelper.MapOptionsToSelectListItems(regions, userLocationViewModel.SelectedRegionId); + + if (formSubmission) + { + if (model?.SelectedCountryId == null) + { + this.ModelState.AddModelError(nameof(model.SelectedCountryId), CommonValidationErrorMessages.CountryRequired); + return this.View("MyAccountChangeLocation", userLocationViewModel); + } + else if (model.SelectedCountryId == 1 && model.SelectedRegionId == null) + { + userLocationViewModel.HasSelectedRegion = true; + this.ModelState.AddModelError(nameof(model.SelectedRegionId), CommonValidationErrorMessages.RegionRequired); + return this.View("MyAccountChangeLocation", userLocationViewModel); + } + else if (model.SelectedCountryId != 1) + { + model.SelectedRegionId = null; + } + + if (model?.SelectedCountryId == 0) + { + if (model.SelectedOtherCountryId != null && model.SelectedOtherCountryId > 0) + { + model.SelectedCountryId = model.SelectedOtherCountryId; + } + else + { + userLocationViewModel.HasSelectedOtherCountry = true; + this.ModelState.AddModelError(nameof(model.SelectedOtherCountryId), CommonValidationErrorMessages.CountryRequired); + return this.View("MyAccountChangeLocation", userLocationViewModel); + } + } + + if (this.ModelState.IsValid) + { + await this.userService.UpdateMyAccountLocationDetailsAsync(this.CurrentUserId, model); + this.ViewBag.SuccessMessage = CommonValidationErrorMessages.LocationDetailsSuccessMessage; + this.ViewBag.MyAction = "MyEmploymentDetails"; + return this.View("SuccessMessageMyAccount"); + } + } + return this.View("MyAccountChangeLocation", userLocationViewModel); } + ////[HttpPost] + ////public async Task UpdateMyAccountLocationDetails(MyAccountLocationViewModel model) + ////{ + //// if (model?.SelectedCountryId == null) + //// { + //// this.ModelState.AddModelError(nameof(model.SelectedCountryId), CommonValidationErrorMessages.CountryRequired); + //// return this.View("MyAccountChangeLocation", model); + //// } + //// else if (model.SelectedCountryId == 1 && model.SelectedRegionId == null) + //// { + //// this.ModelState.AddModelError(nameof(model.SelectedRegionId), CommonValidationErrorMessages.RegionRequired); + //// return this.View("MyAccountChangeLocation", model); + //// } + //// else if (model.SelectedCountryId != 1) + //// { + //// model.SelectedRegionId = null; + //// } + + //// if (model?.SelectedCountryId == 0) + //// { + //// if (model.SelectedOtherCountryId != null && model.SelectedOtherCountryId > 0) + //// { + //// model.SelectedCountryId = model.SelectedOtherCountryId; + //// } + //// else + //// { + //// this.ModelState.AddModelError(nameof(model.SelectedOtherCountryId), CommonValidationErrorMessages.CountryRequired); + //// return this.View("MyAccountChangeLocation", model); + //// } + //// } + + //// if (this.ModelState.IsValid) + //// { + //// await this.userService.UpdateMyAccountLocationDetailsAsync(this.CurrentUserId, model); + //// this.ViewBag.SuccessMessage = CommonValidationErrorMessages.CountrySuccessMessage; + //// return this.View("SuccessMessage"); + //// } + //// else + //// { + //// return this.View("MyAccountChangeLocation", model); + //// } + ////} + /// - /// To update location details. + /// SecurityQuestionsDetails. + /// + /// viewModel. + /// formSubmission. + /// ActionResult. + [HttpGet] + [Route("myaccount/MyAccountSecurityQuestionsDetails")] + public async Task MyAccountSecurityQuestionsDetails([FromQuery] MyAcountSecurityQuestionsViewModel viewModel, bool formSubmission = false) + { + MyAcountSecurityQuestionsViewModel securityViewModel = new MyAcountSecurityQuestionsViewModel(); + var result = await this.loginWizardService.GetSecurityQuestionsModel(this.CurrentUserId); + + if (result != null) + { + if (result.UserSecurityQuestions != null && result.UserSecurityQuestions.Count > 0) + { + securityViewModel.SelectedFirstQuestionId = result.UserSecurityQuestions[0].SecurityQuestionId; + ////securityViewModel.SecurityFirstQuestionAnswerHash = "********"; + securityViewModel.SelectedSecondQuestionId = result.UserSecurityQuestions.Count > 1 ? result.UserSecurityQuestions[1].SecurityQuestionId : 0; + ////securityViewModel.SecuritySecondQuestionAnswerHash = result.UserSecurityQuestions.Count > 1 ? "********" : string.Empty; + securityViewModel.UserSecurityFirstQuestionId = result.UserSecurityQuestions[0].Id; + securityViewModel.UserSecuritySecondQuestionId = result.UserSecurityQuestions.Count > 1 ? result.UserSecurityQuestions[1].Id : 0; + } + + securityViewModel.FirstSecurityQuestions = SelectListHelper.MapSelectListWithSelection(result.SecurityQuestions, Convert.ToString(securityViewModel.SelectedFirstQuestionId)); + securityViewModel.SecondSecurityQuestions = SelectListHelper.MapSelectListWithSelection(result.SecurityQuestions, Convert.ToString(securityViewModel.SelectedSecondQuestionId)); + } + + if (formSubmission && viewModel != null) + { + if (viewModel.SelectedFirstQuestionId == viewModel.SelectedSecondQuestionId) + { + this.ModelState.AddModelError("DuplicateQuestion", CommonValidationErrorMessages.DuplicateQuestion); + return this.View("MyAccountSecurityQuestionsDetails", securityViewModel); + } + + if (viewModel.SelectedFirstQuestionId > 0) + { + this.ModelState.AddModelError(nameof(viewModel.SecurityFirstQuestionAnswerHash), CommonValidationErrorMessages.InvalidSecurityQuestionAnswer); + return this.View("MyAccountSecurityQuestionsDetails", securityViewModel); + } + + if (viewModel.SelectedSecondQuestionId > 0) + { + this.ModelState.AddModelError(nameof(viewModel.SecuritySecondQuestionAnswerHash), CommonValidationErrorMessages.InvalidSecurityQuestionAnswer); + return this.View("MyAccountSecurityQuestionsDetails", securityViewModel); + } + + if (this.ModelState.IsValid) + { + var userSecurityQuestions = new List + { + new UserSecurityQuestionViewModel + { + Id = securityViewModel.UserSecurityFirstQuestionId, + SecurityQuestionId = securityViewModel.SelectedFirstQuestionId, + SecurityQuestionAnswerHash = securityViewModel.SecurityFirstQuestionAnswerHash, + UserId = this.CurrentUserId, + }, + new UserSecurityQuestionViewModel + { + Id = securityViewModel.UserSecuritySecondQuestionId, + SecurityQuestionId = securityViewModel.SelectedSecondQuestionId, + SecurityQuestionAnswerHash = securityViewModel.SecuritySecondQuestionAnswerHash, + UserId = this.CurrentUserId, + }, + }; + + await this.userService.UpdateUserSecurityQuestions(userSecurityQuestions); + + this.ViewBag.SuccessMessage = CommonValidationErrorMessages.SecurityQuestionSuccessMessage; + this.ViewBag.MyAction = "MyAccountSecurity"; + return this.View("SuccessMessageMyAccount"); + } + else + { + return this.View("MyAccountSecurityQuestionsDetails", securityViewModel); + } + } + + return this.View("MyAccountSecurityQuestionsDetails", securityViewModel); + } + + /// + /// To update security questions. /// /// model. /// The . [HttpPost] - public async Task UpdateMyAccountLocationDetails(MyAccountLocationViewModel model) + public async Task UpdateMyAccountSecurityQuestions(MyAcountSecurityQuestionsViewModel model) { + bool duplicatesExist = false; + ////var securityQuestionsViewModel = await this.loginWizardService.GetSecurityQuestionsModel(this.CurrentUserId); + ////if (model.SelectedFirstQuestionId == securityQuestionsViewModel.UserSecurityQuestions[1].SecurityQuestionId) + ////{ + //// duplicatesExist = true; + ////} + ////else if (model.SelectedSecondQuestionId == securityQuestionsViewModel.UserSecurityQuestions[0].SecurityQuestionId) + ////{ + //// duplicatesExist = true; + ////} + + if (model.SelectedFirstQuestionId == model.SelectedSecondQuestionId) + { + duplicatesExist = true; + } + + if (duplicatesExist) + { + this.ModelState.AddModelError("DuplicateQuestion", CommonValidationErrorMessages.DuplicateQuestion); + return this.View("MyAccountSecurityQuestionsDetails", model); + } + if (this.ModelState.IsValid) { - if (model?.SelectedCountryId == 0) + var userSecurityQuestions = new List { - model.SelectedCountryId = model.SelectedOtherCountryId; - } + new UserSecurityQuestionViewModel + { + Id = model.UserSecurityFirstQuestionId, + SecurityQuestionId = model.SelectedFirstQuestionId, + SecurityQuestionAnswerHash = model.SecurityFirstQuestionAnswerHash, + UserId = this.CurrentUserId, + }, + new UserSecurityQuestionViewModel + { + Id = model.UserSecuritySecondQuestionId, + SecurityQuestionId = model.SelectedSecondQuestionId, + SecurityQuestionAnswerHash = model.SecuritySecondQuestionAnswerHash, + UserId = this.CurrentUserId, + }, + }; - if (model.SelectedCountryId != 1) - { - model.SelectedRegionId = null; - } + await this.userService.UpdateUserSecurityQuestions(userSecurityQuestions); - await this.userService.UpdateMyAccountLocationDetailsAsync(this.CurrentUserId, model); - this.ViewBag.SuccessMessage = CommonValidationErrorMessages.CountrySuccessMessage; + this.ViewBag.SuccessMessage = CommonValidationErrorMessages.FirstQuestionSuccessMessage; return this.View("SuccessMessage"); } else { - return this.View("MyAccountChangeLocation", model); + return this.View("MyAccountSecurityQuestionsDetails", model); } } @@ -992,6 +1200,9 @@ public async Task ChangePrimarySpecialty([FromQuery] UserPrimaryS viewModel.PageSize = UserDetailContentPageSize; viewModel.CurrentPage = viewModel.CurrentPage == 0 ? 1 : viewModel.CurrentPage; viewModel.OptionalSpecialtyItem = optionalSpecialty.FirstOrDefault(x => x.Name.ToLower() == "not applicable"); + viewModel.SelectedGradeId = profile.GradeId?.ToString() ?? null; + viewModel.SelectedJobRoleId = profile.JobRoleId; + viewModel.SelectedMedicalCouncilNo = profile.MedicalCouncilNo; if (searchSubmission && string.IsNullOrWhiteSpace(viewModel.FilterText)) { @@ -1053,7 +1264,7 @@ public async Task ChangeStartDate([FromQuery] UserStartDateUpdate var profile = await this.userService.GetUserProfileSummaryAsync(); viewModel.JobStartDate = profile.JobStartDate; - + ////viewModel.SpecialtyId = profile.SelectedPrimarySpecialtyId; if (formSubmission) { if (this.ModelState.IsValid) @@ -1111,45 +1322,6 @@ public async Task ChangeWorkPlace([FromQuery] UserWorkPlaceUpdate return this.View("ChangeWorkPlace", viewModel); } - if (formSubmission && viewModel.SelectedWorkPlaceId.HasValue) - { - await this.userService.UpdateUserEmployment( - new elfhHub.Nhs.Models.Entities.UserEmployment - { - Id = profile.EmploymentId, - UserId = profile.Id, - JobRoleId = profile.JobRoleId, - MedicalCouncilId = profile.MedicalCouncilId, - MedicalCouncilNo = profile.MedicalCouncilNo, - GradeId = profile.GradeId, - SpecialtyId = profile.SpecialtyId, - StartDate = profile.JobStartDate, - LocationId = viewModel.SelectedWorkPlaceId.Value, - }); - - var (cacheExists, loginWizard) = await this.cacheService.TryGetAsync(this.LoginWizardCacheKey); - - if (cacheExists && loginWizard.LoginWizardStagesRemaining.Any(l => l.Id == (int)LoginWizardStageEnum.PlaceOfWork)) - { - await this.loginWizardService.SaveLoginWizardStageActivity(LoginWizardStageEnum.PlaceOfWork, this.CurrentUserId); - - var stagePlaceOfWork = loginWizard.LoginWizardStages.FirstOrDefault(s => s.Id == (int)LoginWizardStageEnum.PlaceOfWork); - loginWizard.LoginWizardStagesCompleted.Add(stagePlaceOfWork); - - var loginWizardViewModel = new LoginWizardStagesViewModel - { - IsFirstLogin = loginWizard.IsFirstLogin, - LoginWizardStages = loginWizard.LoginWizardStages, - LoginWizardStagesCompleted = loginWizard.LoginWizardStagesCompleted, - }; - - await this.cacheService.SetAsync(this.LoginWizardCacheKey, Newtonsoft.Json.JsonConvert.SerializeObject(loginWizardViewModel)); - } - - this.ViewBag.SuccessMessage = "Your employment details have been updated"; - return this.View("SuccessMessage"); - } - if (!string.IsNullOrWhiteSpace(viewModel.FilterText)) { var locations = await this.locationService.GetPagedFilteredAsync(viewModel.FilterText, viewModel.CurrentPage, viewModel.PageSize); @@ -1158,6 +1330,54 @@ await this.userService.UpdateUserEmployment( viewModel.HasItems = locations.Item1 > 0; } + if (formSubmission) + { + if (viewModel.SelectedWorkPlaceId.HasValue) + { + await this.userService.UpdateUserEmployment( + new elfhHub.Nhs.Models.Entities.UserEmployment + { + Id = profile.EmploymentId, + UserId = profile.Id, + JobRoleId = profile.JobRoleId, + MedicalCouncilId = profile.MedicalCouncilId, + MedicalCouncilNo = profile.MedicalCouncilNo, + GradeId = profile.GradeId, + SpecialtyId = profile.SpecialtyId, + StartDate = profile.JobStartDate, + LocationId = viewModel.SelectedWorkPlaceId.Value, + }); + + var (cacheExists, loginWizard) = await this.cacheService.TryGetAsync(this.LoginWizardCacheKey); + + if (cacheExists && loginWizard.LoginWizardStagesRemaining.Any(l => l.Id == (int)LoginWizardStageEnum.PlaceOfWork)) + { + await this.loginWizardService.SaveLoginWizardStageActivity(LoginWizardStageEnum.PlaceOfWork, this.CurrentUserId); + + var stagePlaceOfWork = loginWizard.LoginWizardStages.FirstOrDefault(s => s.Id == (int)LoginWizardStageEnum.PlaceOfWork); + loginWizard.LoginWizardStagesCompleted.Add(stagePlaceOfWork); + + var loginWizardViewModel = new LoginWizardStagesViewModel + { + IsFirstLogin = loginWizard.IsFirstLogin, + LoginWizardStages = loginWizard.LoginWizardStages, + LoginWizardStagesCompleted = loginWizard.LoginWizardStagesCompleted, + }; + + await this.cacheService.SetAsync(this.LoginWizardCacheKey, Newtonsoft.Json.JsonConvert.SerializeObject(loginWizardViewModel)); + } + + this.ViewBag.SuccessMessage = CommonValidationErrorMessages.EmploymentDetailsUpdated; + this.ViewBag.MyAction = "MyEmploymentDetails"; + return this.View("SuccessMessageMyAccount"); + } + else + { + this.ModelState.AddModelError(nameof(viewModel.SelectedWorkPlaceId), CommonValidationErrorMessages.WorkPlace); + return this.View("ChangeWorkPlace", viewModel); + } + } + return this.View("ChangeWorkPlace", viewModel); } diff --git a/LearningHub.Nhs.WebUI/Helpers/CommonValidationErrorMessages.cs b/LearningHub.Nhs.WebUI/Helpers/CommonValidationErrorMessages.cs index c9b3aa7bc..440692fae 100644 --- a/LearningHub.Nhs.WebUI/Helpers/CommonValidationErrorMessages.cs +++ b/LearningHub.Nhs.WebUI/Helpers/CommonValidationErrorMessages.cs @@ -229,5 +229,30 @@ public static class CommonValidationErrorMessages /// Message if the validation token expired. /// public const string EmailChangeValidationTokenInvalidMessage = "We cannot find the page you are looking for"; + + /// + /// Message if the validation token expired. + /// + public const string InvalidSecurityQuestionAnswer = "Enter an answer"; + + /// + /// Message if the validation token expired. + /// + public const string EmploymentDetailsUpdated = "Your employment details has been changed"; + + /// + /// security question Success Message. + /// + public const string SecurityQuestionSuccessMessage = "Your security questions has been changed"; + + /// + /// location Success Message. + /// + public const string LocationDetailsSuccessMessage = "Your location details has been changed"; + + /// + /// location Success Message. + /// + public const string PersonalDetailsSuccessMessage = "Your personal details has been changed"; } } diff --git a/LearningHub.Nhs.WebUI/Helpers/SelectListHelper.cs b/LearningHub.Nhs.WebUI/Helpers/SelectListHelper.cs index 089665bfe..1dcd3f53e 100644 --- a/LearningHub.Nhs.WebUI/Helpers/SelectListHelper.cs +++ b/LearningHub.Nhs.WebUI/Helpers/SelectListHelper.cs @@ -20,5 +20,16 @@ public static IEnumerable MapOptionsToSelectListItems(IEnumerabl { return options.Select(o => new SelectListItem(o.Name, o.Id.ToString(), o.Id == selectedId)).ToList(); } + + /// + /// MapSelectListWithSelection. + /// + /// options. + /// selectedId. + /// SelectListItem. + public static IEnumerable MapSelectListWithSelection(IEnumerable options, string selectedId = null) + { + return options.Select(o => new SelectListItem(o.Text, o.Value, o.Value == selectedId)).ToList(); + } } } diff --git a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs index 4889d7fb8..35bf84302 100644 --- a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs +++ b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs @@ -28,7 +28,7 @@ public static IEnumerable GetGroupedMenus() Text = "Personal details", Controller = "MyAccount", Action = "Index", - IsActive = route => MatchRoute(route, "MyAccount", "PersonalDetails"), + IsActive = route => MatchRoute(route, "MyAccount", "Index"), }, new SideNavigationItem { diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountLocationViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountLocationViewModel.cs index 1e9a97b61..58bd757ae 100644 --- a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountLocationViewModel.cs +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountLocationViewModel.cs @@ -2,8 +2,6 @@ { using System.Collections.Generic; using System.ComponentModel; - using System.ComponentModel.DataAnnotations; - using elfhHub.Nhs.Models.Common; using Microsoft.AspNetCore.Mvc.Rendering; using NHSUKViewComponents.Web.ViewModels; @@ -15,14 +13,12 @@ public class MyAccountLocationViewModel /// /// Gets or sets the country id. /// - [Required(ErrorMessage = "Select a country.")] [DisplayName("Country")] public int? SelectedCountryId { get; set; } /// /// Gets or sets the region id. /// - [Required(ErrorMessage = "Select a region.")] [DisplayName("Region")] public int? SelectedRegionId { get; set; } @@ -39,14 +35,17 @@ public class MyAccountLocationViewModel /// /// Gets or sets the country id. /// - ////[Required(ErrorMessage = "Select a country.")] - ////[DisplayName("Country")] public int? SelectedOtherCountryId { get; set; } /// /// Gets or sets a value indicating whether SelectedOtherCountry. /// - public bool SelectedOtherCountry { get; set; } + public bool HasSelectedOtherCountry { get; set; } + + /// + /// Gets or sets a value indicating whether SelectedRegion. + /// + public bool HasSelectedRegion { get; set; } /// /// Gets or sets the Country. diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs index 05abe5e71..194bcc89a 100644 --- a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs @@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations; using LearningHub.Nhs.WebUI.Attributes; using LearningHub.Nhs.WebUI.Helpers; + using LearningHub.Nhs.WebUI.Validation; /// /// Defines the . @@ -60,5 +61,15 @@ public class MyAccountPersonalDetailsViewModel /// Gets or sets the new primary email address. /// public string NewPrimaryEmailAddress { get; set; } + + /// + /// Gets or sets the SecondaryEmailAddress. + /// + [DataType(DataType.EmailAddress)] + [NotEqual("PrimaryEmailAddress", ErrorMessage = CommonValidationErrorMessages.SecondaryEmailShouldNotBeSame)] + [MaxLength(100, ErrorMessage = CommonValidationErrorMessages.TooLongEmail)] + [EmailAddress(ErrorMessage = CommonValidationErrorMessages.InvalidEmail)] + [NoWhitespace(ErrorMessage = CommonValidationErrorMessages.WhitespaceInEmail)] + public string SecondaryEmailAddress { get; set; } } } diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountSecurityViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountSecurityViewModel.cs index c27467f71..d1a26f4c1 100644 --- a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountSecurityViewModel.cs +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountSecurityViewModel.cs @@ -27,10 +27,10 @@ public class MyAccountSecurityViewModel /// public string SecuritySecondQuestion { get; set; } - /// - /// Gets or sets the LastUpdated. - /// - public DateTimeOffset LastUpdated { get; set; } + /////// + /////// Gets or sets the LastUpdated. + /////// + ////public DateTimeOffset LastUpdated { get; set; } /// /// Gets or sets the PasswordHash. @@ -40,6 +40,6 @@ public class MyAccountSecurityViewModel /// /// Gets or sets the SecurityQuestionLastUpdated. /// - public DateTimeOffset? SecurityQuestionLastUpdated { get; set; } + public string SecurityQuestionLastUpdated { get; set; } } } diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAcountSecurityQuestionsViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAcountSecurityQuestionsViewModel.cs new file mode 100644 index 000000000..7712ae470 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAcountSecurityQuestionsViewModel.cs @@ -0,0 +1,54 @@ +namespace LearningHub.Nhs.WebUI.Models.UserProfile +{ + using System.Collections.Generic; + using System.ComponentModel.DataAnnotations; + using elfhHub.Nhs.Models.Common; + using Microsoft.AspNetCore.Mvc.Rendering; + using NHSUKViewComponents.Web.ViewModels; + + /// + /// Defines the . + /// + public class MyAcountSecurityQuestionsViewModel + { + /// + /// Gets or sets selectedQuestion. + /// + public int SelectedFirstQuestionId { get; set; } + + /// + /// Gets or sets selectedQuestion. + /// + public int SelectedSecondQuestionId { get; set; } + + /// + /// Gets or sets the security question answer hash. + /// + public string SecurityFirstQuestionAnswerHash { get; set; } + + /// + /// Gets or sets the security question answer hash. + /// + public string SecuritySecondQuestionAnswerHash { get; set; } + + /// + /// Gets or sets the FirstSecurityQuestions. + /// + public IEnumerable FirstSecurityQuestions { get; set; } + + /// + /// Gets or sets the SecondSecurityQuestions. + /// + public IEnumerable SecondSecurityQuestions { get; set; } + + /// + /// Gets or sets the UserSecurityFirstQuestionId. + /// + public int UserSecurityFirstQuestionId { get; set; } + + /// + /// Gets or sets the UserSecurityFirstQuestionId. + /// + public int UserSecuritySecondQuestionId { get; set; } + } +} diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/UserPrimarySpecialtyUpdateViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/UserPrimarySpecialtyUpdateViewModel.cs index 8dd1546ed..5c91bd661 100644 --- a/LearningHub.Nhs.WebUI/Models/UserProfile/UserPrimarySpecialtyUpdateViewModel.cs +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/UserPrimarySpecialtyUpdateViewModel.cs @@ -36,6 +36,21 @@ public class UserPrimarySpecialtyUpdateViewModel : PagingViewModel /// public GenericListViewModel OptionalSpecialtyItem { get; set; } + /// + /// Gets or sets the selected job role id. + /// + public int? SelectedJobRoleId { get; set; } + + /// + /// Gets or sets the selected grade id. + /// + public string SelectedGradeId { get; set; } + + /// + /// Gets or sets the selected medical council number. + /// + public string SelectedMedicalCouncilNo { get; set; } + /// /// sets the list of radio specialty. /// diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/UserStartDateUpdateViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/UserStartDateUpdateViewModel.cs index 8d45071cd..372427781 100644 --- a/LearningHub.Nhs.WebUI/Models/UserProfile/UserStartDateUpdateViewModel.cs +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/UserStartDateUpdateViewModel.cs @@ -30,6 +30,16 @@ public class UserStartDateUpdateViewModel : IValidatableObject /// public int? Year { get; set; } + /////// + /////// Gets or sets filter text. + /////// + ////public string FilterText { get; set; } + + /// + /// Gets or sets the selected primary specialty id. + /// + public int? SelectedPrimarySpecialtyId { get; set; } + /// /// Gets or sets the GetDate. /// diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/notification/notification.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/notification/notification.vue index 25ef12656..84fb2eb0c 100644 --- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/notification/notification.vue +++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/notification/notification.vue @@ -1,7 +1,7 @@