diff --git a/.github/workflows/sonar-scan.yml b/.github/workflows/sonar-scan.txt similarity index 92% rename from .github/workflows/sonar-scan.yml rename to .github/workflows/sonar-scan.txt index 42219716c..28ed22e18 100644 --- a/.github/workflows/sonar-scan.yml +++ b/.github/workflows/sonar-scan.txt @@ -41,6 +41,6 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} shell: powershell run: | - .\.sonar\scanner\dotnet-sonarscanner begin /k:"bcgov_hets" /o:"bcgov-sonarcloud" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" + .\.sonar\scanner\dotnet-sonarscanner begin /k:"bcgov_hets" /o:"bcgov-sonarcloud" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.coverage.exclusions=**\Server\**\* /d:sonar.cpd.exclusions=**\Server\**\* dotnet build Server .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" \ No newline at end of file diff --git a/.pipeline/lib/config.js b/.pipeline/lib/config.js index c2343aa5f..c4b8067a9 100644 --- a/.pipeline/lib/config.js +++ b/.pipeline/lib/config.js @@ -1,7 +1,7 @@ "use strict"; const options = require("@bcgov/pipeline-cli").Util.parseArguments(); const changeId = options.pr; //aka pull-request -const version = "1.10.1"; +const version = "1.10.9"; const name = "hets"; Object.assign(options.git, { owner: "ychung-mot", repository: "hets" }); diff --git a/.sonarcloud.properties b/.sonarcloud.properties index 0f1110d29..552c54de7 100644 --- a/.sonarcloud.properties +++ b/.sonarcloud.properties @@ -2,7 +2,8 @@ sonar.projectName=hets # Path to sources sonar.sources=Server,client/src -#sonar.exclusions= +sonar.coverage.exclusions=Server/**/* +sonar.cpd.exclusions=Server/**/* #sonar.inclusions= # Source encoding diff --git a/Server/HetsApi/Controllers/DistrictController.cs b/Server/HetsApi/Controllers/DistrictController.cs index 07193c93b..3a319ec6f 100644 --- a/Server/HetsApi/Controllers/DistrictController.cs +++ b/Server/HetsApi/Controllers/DistrictController.cs @@ -15,6 +15,7 @@ using Hangfire.Common; using HetsData.Dtos; using AutoMapper; +using HetsCommon; namespace HetsApi.Controllers { @@ -90,10 +91,15 @@ public virtual ActionResult> DistrictOwnersGet([FromRoute]int id) [AllowAnonymous] public virtual ActionResult> DistrictLocalAreasGet([FromRoute]int id) { + var now = DateTime.UtcNow; + var nowDate = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.Year, now.Month, now.Day, 0, 0, 0, DateTimeKind.Unspecified)); + List localAreas = _context.HetLocalAreas.AsNoTracking() - .Where(x => x.ServiceArea.District.DistrictId == id && - x.StartDate <= DateTime.UtcNow.Date && - (x.EndDate > DateTime.UtcNow.Date || x.EndDate == null)) + .Where(x => + x.ServiceArea.District.DistrictId == id + && x.StartDate <= nowDate + && (x.EndDate > nowDate || x.EndDate == null)) .OrderBy(x => x.Name) .ToList(); @@ -126,7 +132,10 @@ public virtual ActionResult RolloverStatusGet([FromRoute]int var progress = _context.HetRolloverProgresses.FirstOrDefault(a => a.DistrictId == id); // not found - if (progress == null) return new ObjectResult(new HetsResponse(new RolloverProgressDto { DistrictId = id, ProgressPercentage = null })); + if (progress == null) + return new ObjectResult( + new HetsResponse( + new RolloverProgressDto { DistrictId = id, ProgressPercentage = null })); if (!jobExists) { @@ -134,7 +143,9 @@ public virtual ActionResult RolloverStatusGet([FromRoute]int } // get status of current district - return new ObjectResult(new HetsResponse(new RolloverProgressDto { DistrictId = id, ProgressPercentage = progress.ProgressPercentage })); + return new ObjectResult( + new HetsResponse( + new RolloverProgressDto { DistrictId = id, ProgressPercentage = progress.ProgressPercentage })); } private string GetJobFingerprint(Hangfire.Common.Job job) @@ -203,18 +214,22 @@ public virtual ActionResult AnnualRolloverGet([FromRoute]int bool exists = _context.HetDistricts.Any(a => a.DistrictId == id); // not found - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // determine the current fiscal year DateTime fiscalStart; - - if (DateTime.UtcNow.Month == 1 || DateTime.UtcNow.Month == 2 || DateTime.UtcNow.Month == 3) + DateTime now = DateTime.Now; + if (now.Month == 1 || now.Month == 2 || now.Month == 3) { - fiscalStart = new DateTime(DateTime.UtcNow.AddYears(-1).Year, 4, 1); + fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.AddYears(-1).Year, 4, 1, 0, 0, 0, DateTimeKind.Unspecified)); } else { - fiscalStart = new DateTime(DateTime.UtcNow.Year, 4, 1); + fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.Year, 4, 1, 0, 0, 0, DateTimeKind.Unspecified)); } // get record and ensure it isn't already processing diff --git a/Server/HetsApi/Controllers/EquipmentController.cs b/Server/HetsApi/Controllers/EquipmentController.cs index 0ab92011f..a4ce1f344 100644 --- a/Server/HetsApi/Controllers/EquipmentController.cs +++ b/Server/HetsApi/Controllers/EquipmentController.cs @@ -18,6 +18,9 @@ using HetsData.Dtos; using AutoMapper; using HetsCommon; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal; +using DocumentFormat.OpenXml.Drawing; +using System.Reflection.Metadata.Ecma335; namespace HetsApi.Controllers { @@ -101,25 +104,31 @@ public virtual ActionResult> EquipmentGetLiteTs() // get active status int? statusId = StatusHelper.GetStatusId(HetEquipment.StatusApproved, "equipmentStatus", _context); - if (statusId == null) return new BadRequestObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusId == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // get fiscal year HetDistrictStatus status = _context.HetDistrictStatuses.AsNoTracking() .First(x => x.DistrictId == districtId); int? fiscalYear = status.CurrentFiscalYear; - if (fiscalYear == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (fiscalYear == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // fiscal year in the status table stores the "start" of the year - DateTime fiscalYearStart = new DateTime((int)fiscalYear, 3, 31); + DateTime fiscalYearStart = DateUtils.ConvertPacificToUtcTime( + new DateTime((int)fiscalYear, 3, 31, 0, 0, 0, DateTimeKind.Unspecified)); // get all active owners for this district (and any projects they're associated with) var equipments = _context.HetRentalAgreements.AsNoTracking() .Include(x => x.Project) .Include(x => x.Equipment) - .Where(x => x.Equipment.LocalArea.ServiceArea.DistrictId == districtId && - x.Equipment.EquipmentStatusTypeId == statusId && - x.Project.DbCreateTimestamp > fiscalYearStart) + .Where(x => + x.Equipment.LocalArea.ServiceArea.DistrictId == districtId + && x.Equipment.EquipmentStatusTypeId == statusId + && x.Project.DbCreateTimestamp > fiscalYearStart) .ToList() .GroupBy(x => x.Equipment, (e, agreements) => new EquipmentLiteList { @@ -283,25 +292,31 @@ public virtual ActionResult EquipmentIdPut([FromRoute]int id, [Fro // update equipment record equipment.ConcurrencyControlNumber = item.ConcurrencyControlNumber; - equipment.ApprovedDate = item.ApprovedDate; + if (item.ApprovedDate is DateTime approvedDateUtc) + { + equipment.ApprovedDate = DateUtils.AsUTC(approvedDateUtc); + } equipment.EquipmentCode = item.EquipmentCode; equipment.Make = item.Make; equipment.Model = item.Model; equipment.Operator = item.Operator; - equipment.ReceivedDate = item.ReceivedDate; + equipment.ReceivedDate = DateUtils.AsUTC(item.ReceivedDate); equipment.LicencePlate = item.LicencePlate; equipment.SerialNumber = item.SerialNumber; equipment.Size = item.Size; equipment.YearsOfService = item.YearsOfService; equipment.Year = item.Year; - equipment.LastVerifiedDate = item.LastVerifiedDate; + equipment.LastVerifiedDate = DateUtils.AsUTC(item.LastVerifiedDate); equipment.IsSeniorityOverridden = item.IsSeniorityOverridden; equipment.SeniorityOverrideReason = item.SeniorityOverrideReason; equipment.Type = item.Type; equipment.ServiceHoursLastYear = item.ServiceHoursLastYear; equipment.ServiceHoursTwoYearsAgo = item.ServiceHoursTwoYearsAgo; equipment.ServiceHoursThreeYearsAgo = item.ServiceHoursThreeYearsAgo; - equipment.SeniorityEffectiveDate = item.SeniorityEffectiveDate; + if (item.SeniorityEffectiveDate is DateTime seniorityEffectiveDateUtc) + { + equipment.SeniorityEffectiveDate = DateUtils.AsUTC(seniorityEffectiveDateUtc); + } equipment.LicencedGvw = item.LicencedGvw; equipment.LegalCapacity = item.LegalCapacity; equipment.PupLegalCapacity = item.PupLegalCapacity; @@ -511,14 +526,16 @@ public virtual ActionResult EquipmentPost([FromBody]EquipmentDto i // determine end of current fiscal year DateTime fiscalEnd; - - if (DateTime.UtcNow.Month == 1 || DateTime.UtcNow.Month == 2 || DateTime.UtcNow.Month == 3) + DateTime now = DateTime.Now; + if (now.Month == 1 || now.Month == 2 || now.Month == 3) { - fiscalEnd = new DateTime(DateTime.UtcNow.Year, 3, 31); + fiscalEnd = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.Year, 3, 31, 0, 0, 0, DateTimeKind.Unspecified)); } else { - fiscalEnd = new DateTime(DateTime.UtcNow.AddYears(1).Year, 3, 31); + fiscalEnd = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.AddYears(1).Year, 3, 31, 0, 0, 0, DateTimeKind.Unspecified)); } // is this a leap year? @@ -656,18 +673,29 @@ private string RecurseConfigJson(IConfigurationSection scoringRules) [HttpGet] [Route("search")] [RequiresPermission(HetPermission.Login)] - public virtual ActionResult EquipmentSearchGet([FromQuery]string localAreas, [FromQuery]string types, - [FromQuery]string equipmentAttachment, [FromQuery]int? owner, [FromQuery]string status, - [FromQuery]bool? hired, [FromQuery]DateTime? notVerifiedSinceDate, - [FromQuery]string equipmentId = null, [FromQuery]string ownerName = null, - [FromQuery]string projectName = null, [FromQuery]bool twentyYears = false) + public virtual ActionResult EquipmentSearchGet( + [FromQuery]string localAreas, + [FromQuery]string types, + [FromQuery]string equipmentAttachment, + [FromQuery]int? owner, + [FromQuery]string status, + [FromQuery]bool? hired, + [FromQuery]DateTime? notVerifiedSinceDate, + [FromQuery]string equipmentId = null, + [FromQuery]string ownerName = null, + [FromQuery]string projectName = null, + [FromQuery]bool twentyYears = false) { int?[] localAreasArray = ArrayHelper.ParseIntArray(localAreas); int?[] typesArray = ArrayHelper.ParseIntArray(types); // get agreement status - int? agreementStatusId = StatusHelper.GetStatusId(HetRentalAgreement.StatusActive, "rentalAgreementStatus", _context); - if (agreementStatusId == null) return new BadRequestObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + int? agreementStatusId = StatusHelper.GetStatusId( + HetRentalAgreement.StatusActive, "rentalAgreementStatus", _context); + + if (agreementStatusId == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // get initial results - must be limited to user's district int? districtId = UserAccountHelper.GetUsersDistrictId(_context); @@ -684,15 +712,16 @@ public virtual ActionResult EquipmentSearchGet([FromQuery]stri .Where(x => x.LocalArea.ServiceArea.DistrictId.Equals(districtId)); // filter results based on search criteria - if (localAreasArray != null && localAreasArray.Length > 0) + if (!IsArrayEmpty(localAreasArray)) { data = data.Where(x => localAreasArray.Contains(x.LocalArea.LocalAreaId)); } if (equipmentAttachment != null) { - data = data.Where(x => x.HetEquipmentAttachments - .Any(y => y.TypeName.ToLower().Contains(equipmentAttachment.ToLower()))); + data = data.Where(x => + x.HetEquipmentAttachments.Any(y => + y.TypeName.ToLower().Contains(equipmentAttachment.ToLower()))); } if (owner != null) @@ -700,13 +729,7 @@ public virtual ActionResult EquipmentSearchGet([FromQuery]stri data = data.Where(x => x.Owner.OwnerId == owner); } - if (ownerName != null) - { - data = data.Where(x => - x.Owner.OrganizationName.ToLower().Contains(ownerName.ToLower()) || - x.Owner.DoingBusinessAs.ToLower().Contains(ownerName.ToLower()) - ); - } + data = WithOwnerName(data, ownerName); if (status != null) { @@ -718,38 +741,17 @@ public virtual ActionResult EquipmentSearchGet([FromQuery]stri } } - if (projectName != null) - { - IQueryable hiredEquipmentQuery = _context.HetRentalAgreements.AsNoTracking() - .Where(x => x.Equipment.LocalArea.ServiceArea.DistrictId.Equals(districtId)) - .Where(agreement => agreement.RentalAgreementStatusTypeId == agreementStatusId) - .Select(agreement => agreement.EquipmentId) - .Distinct(); - - data = data.Where(e => hiredEquipmentQuery.Contains(e.EquipmentId)); - - data = data.Where(x => x.HetRentalAgreements - .Any(y => y.Project.Name.ToLower().Contains(projectName.ToLower()))); - } - else if (hired == true) - { - IQueryable hiredEquipmentQuery = _context.HetRentalAgreements.AsNoTracking() - .Where(x => x.Equipment.LocalArea.ServiceArea.DistrictId.Equals(districtId)) - .Where(agreement => agreement.RentalAgreementStatusTypeId == agreementStatusId) - .Select(agreement => agreement.EquipmentId) - .Distinct(); - - data = data.Where(e => hiredEquipmentQuery.Contains(e.EquipmentId)); - } + data = QueryByProjectNameOrHired(data, projectName, hired, districtId, agreementStatusId); - if (typesArray != null && typesArray.Length > 0) + if (!IsArrayEmpty(typesArray)) { data = data.Where(x => typesArray.Contains(x.DistrictEquipmentType.DistrictEquipmentTypeId)); } - if (notVerifiedSinceDate != null) + if (notVerifiedSinceDate is DateTime notVerifiedSince) { - data = data.Where(x => x.LastVerifiedDate < notVerifiedSinceDate); + DateTime notVerifiedSinceUTC = DateUtils.AsUTC(notVerifiedSince); + data = data.Where(x => x.LastVerifiedDate < notVerifiedSinceUTC); } // Ministry refer to the EquipmentCode as the "equipmentId" - its not the db id @@ -759,22 +761,18 @@ public virtual ActionResult EquipmentSearchGet([FromQuery]stri } // convert Equipment Model to the "EquipmentLite" Model - SeniorityScoringRules scoringRules = new SeniorityScoringRules(_configuration, (errMessage, ex) => { - _logger.LogError(errMessage); - _logger.LogError(ex.ToString()); + SeniorityScoringRules scoringRules = new(_configuration, (errMessage, ex) => { + _logger.LogError("{errMessage}", errMessage); + _logger.LogError("{exception}", ex.ToString()); }); - List result = new List(); + + List result = new(); var dataList = data.ToList(); // HETS-942 - Search for Equipment > 20 yrs // ** only return equipment that are 20 years and older (using the equipment Year) - if (twentyYears) - { - var twentyYearsInt = DateTime.Now.Year - 20; - dataList = dataList.Where(x => string.IsNullOrWhiteSpace(x.Year) || int.Parse(x.Year) <= twentyYearsInt) - .ToList(); - } + dataList = EquipmentsOlderTwentyYears(dataList, twentyYears); foreach (HetEquipment item in dataList) { @@ -785,6 +783,56 @@ public virtual ActionResult EquipmentSearchGet([FromQuery]stri return new ObjectResult(new HetsResponse(result)); } + private static bool IsArrayEmpty(int?[] arr) + { + return arr is null || arr.Length == 0; + } + + private static IQueryable WithOwnerName(IQueryable data, string ownerName) + { + if (ownerName == null) return data; + return data.Where(x => + x.Owner.OrganizationName.ToLower().Contains(ownerName.ToLower()) + || x.Owner.DoingBusinessAs.ToLower().Contains(ownerName.ToLower())); + } + + private static List EquipmentsOlderTwentyYears(List equipments, bool twentyYears) + { + if (twentyYears) + { + var twentyYearsInt = DateTime.Now.Year - 20; + return equipments + .Where(x => string.IsNullOrWhiteSpace(x.Year) || int.Parse(x.Year) <= twentyYearsInt) + .ToList(); + } + return equipments; + } + + private IQueryable QueryByProjectNameOrHired( + IQueryable data, + string projectName, + bool? hired, + int? districtId, + int? agreementStatusId) + { + if (projectName is null && hired != true) return data; + + IQueryable hiredEquipmentQuery = _context.HetRentalAgreements.AsNoTracking() + .Where(x => x.Equipment.LocalArea.ServiceArea.DistrictId.Equals(districtId)) + .Where(agreement => agreement.RentalAgreementStatusTypeId == agreementStatusId) + .Select(agreement => agreement.EquipmentId) + .Distinct(); + + data = data.Where(e => hiredEquipmentQuery.Contains(e.EquipmentId)); + + if (projectName is not null) + { + return data.Where(x => x.HetRentalAgreements + .Any(y => y.Project.Name.ToLower().Contains(projectName.ToLower()))); + } + return data; + } + #endregion #region Clone Project Agreements @@ -1149,21 +1197,23 @@ public virtual ActionResult> EquipmentIdAttachmentsGet([Fro bool exists = _context.HetEquipments.Any(a => a.EquipmentId == id); // not found - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); HetEquipment equipment = _context.HetEquipments.AsNoTracking() .Include(x => x.HetDigitalFiles) .First(a => a.EquipmentId == id); // extract the attachments and update properties for UI - List attachments = new List(); + List attachments = new(); foreach (HetDigitalFile attachment in equipment.HetDigitalFiles) { if (attachment != null) { attachment.FileSize = attachment.FileContents.Length; - attachment.LastUpdateTimestamp = attachment.AppLastUpdateTimestamp; + attachment.LastUpdateTimestamp = DateUtils.AsUTC(attachment.AppLastUpdateTimestamp); attachment.LastUpdateUserid = attachment.AppLastUpdateUserid; // don't send the file content @@ -1173,7 +1223,8 @@ public virtual ActionResult> EquipmentIdAttachmentsGet([Fro } } - return new ObjectResult(new HetsResponse(_mapper.Map>(attachments))); + return new ObjectResult( + new HetsResponse(_mapper.Map>(attachments))); } #endregion @@ -1215,7 +1266,7 @@ public virtual ActionResult> EquipmentIdHistoryPost([FromRoute]int if (exists) { - HetHistory history = new HetHistory + HetHistory history = new() { HistoryId = 0, HistoryText = item.HistoryText, @@ -1340,7 +1391,10 @@ public virtual ActionResult> EquipmentIdNotePost([FromRoute]int id [HttpGet] [Route("seniorityListDoc")] [RequiresPermission(HetPermission.Login)] - public virtual IActionResult EquipmentSeniorityListDocGet([FromQuery]string localAreas, [FromQuery]string types, [FromQuery]bool counterCopy = false) + public virtual IActionResult EquipmentSeniorityListDocGet( + [FromQuery]string localAreas, + [FromQuery]string types, + [FromQuery]bool counterCopy = false) { int?[] localAreasArray = ArrayHelper.ParseIntArray(localAreas); int?[] typesArray = ArrayHelper.ParseIntArray(types); @@ -1352,30 +1406,30 @@ public virtual IActionResult EquipmentSeniorityListDocGet([FromQuery]string loca HetDistrictStatus districtStatus = _context.HetDistrictStatuses.AsNoTracking() .FirstOrDefault(x => x.DistrictId == districtId); - if (districtStatus?.NextFiscalYear == null) return new BadRequestObjectResult(new HetsResponse("HETS-30", ErrorViewModel.GetDescription("HETS-30", _configuration))); + if (districtStatus?.NextFiscalYear == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-30", ErrorViewModel.GetDescription("HETS-30", _configuration))); //// HETS-1195: Adjust seniority list and rotation list for lists hired between Apr1 and roll over //// ** Need to use the "rollover date" to ensure we don't include records created //// after April 1 (but before rollover) - //DateTime fiscalEnd = district.RolloverEndDate ?? new DateTime(0001, 01, 01, 00, 00, 00); - //int fiscalYear = Convert.ToInt32(district.NextFiscalYear); // status table uses the start of the year - - //fiscalEnd = fiscalEnd == new DateTime(0001, 01, 01, 00, 00, 00) ? - // new DateTime(fiscalYear, DateTime.UtcNow.Month, DateTime.UtcNow.Day, 23, 59, 59) : - // new DateTime(fiscalYear, fiscalEnd.Month, fiscalEnd.Day, 23, 59, 59); + DateTime fiscalStart = DateUtils.AsUTC( + districtStatus.RolloverEndDate ?? new DateTime(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc)); - DateTime fiscalStart = districtStatus.RolloverEndDate ?? new DateTime(0001, 01, 01, 00, 00, 00); int fiscalYear = Convert.ToInt32(districtStatus.NextFiscalYear); - if (fiscalStart == new DateTime(0001, 01, 01, 00, 00, 00)) + if (fiscalStart == new DateTime(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc)) { fiscalYear = Convert.ToInt32(districtStatus.NextFiscalYear); // status table uses the start of the year - fiscalStart = new DateTime(fiscalYear - 1, 4, 1); + fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(fiscalYear - 1, 4, 1, 0, 0, 0, DateTimeKind.Unspecified)); } // get status id int? statusId = StatusHelper.GetStatusId(HetEquipment.StatusApproved, "equipmentStatus", _context); - if (statusId == null) return new BadRequestObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusId == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // get equipment record IQueryable data = _context.HetEquipments.AsNoTracking() @@ -1414,12 +1468,12 @@ public virtual IActionResult EquipmentSeniorityListDocGet([FromQuery]string loca // ********************************************************************** // convert Equipment Model to Pdf View Model // ********************************************************************** - SeniorityListReportViewModel seniorityList = new SeniorityListReportViewModel(); - SeniorityScoringRules scoringRules = new SeniorityScoringRules(_configuration, (errMessage, ex) => { + SeniorityListReportViewModel seniorityList = new(); + SeniorityScoringRules scoringRules = new(_configuration, (errMessage, ex) => { _logger.LogError(errMessage); _logger.LogError(ex.ToString()); }); - SeniorityListRecord listRecord = new SeniorityListRecord(); + SeniorityListRecord listRecord = new(); // manage the rotation list data int lastCalledEquipmentId = 0; @@ -1428,18 +1482,9 @@ public virtual IActionResult EquipmentSeniorityListDocGet([FromQuery]string loca foreach (HetEquipment item in items) { - if (listRecord.LocalAreaName != item.LocalArea.Name || - listRecord.DistrictEquipmentTypeName != item.DistrictEquipmentType.DistrictEquipmentName) + if (IsListRecordDifferent(listRecord, item.LocalArea.Name, item.DistrictEquipmentType.DistrictEquipmentName)) { - if (!string.IsNullOrEmpty(listRecord.LocalAreaName)) - { - if (seniorityList.SeniorityListRecords == null) - { - seniorityList.SeniorityListRecords = new List(); - } - - seniorityList.SeniorityListRecords.Add(listRecord); - } + seniorityList.SeniorityListRecords = AddSeniorityListRecord(seniorityList.SeniorityListRecords, listRecord); listRecord = new SeniorityListRecord { @@ -1451,65 +1496,49 @@ public virtual IActionResult EquipmentSeniorityListDocGet([FromQuery]string loca SeniorityList = new List() }; - if (item.LocalArea.ServiceArea?.District != null) - { - listRecord.DistrictName = item.LocalArea.ServiceArea.District.Name; - } + listRecord.DistrictName = GetListRecordDistrictName(listRecord.DistrictName, item.LocalArea.ServiceArea?.District); // get the rotation info for the first block - if (item.BlockNumber != null) currentBlock = (int) item.BlockNumber; + currentBlock = GetCurrentBlock(currentBlock, item.BlockNumber); lastCalledEquipmentId = GetLastCalledEquipmentId(item.LocalArea.LocalAreaId, item.DistrictEquipmentType.DistrictEquipmentTypeId, currentBlock, fiscalStart); } - else if (item.BlockNumber != null && currentBlock != item.BlockNumber) + else if (IsBlockNumberDifferent(currentBlock, item.BlockNumber)) { // get the rotation info for the next block - currentBlock = (int)item.BlockNumber; + currentBlock = GetCurrentBlock(currentBlock, item.BlockNumber); lastCalledEquipmentId = GetLastCalledEquipmentId(item.LocalArea.LocalAreaId, item.DistrictEquipmentType.DistrictEquipmentTypeId, currentBlock, fiscalStart); } - listRecord.SeniorityList.Add(SeniorityListHelper.ToSeniorityViewModel(item, scoringRules, lastCalledEquipmentId, _context)); + listRecord.SeniorityList.Add( + SeniorityListHelper.ToSeniorityViewModel(item, scoringRules, lastCalledEquipmentId, _context)); } // add last record - if (!string.IsNullOrEmpty(listRecord.LocalAreaName)) - { - if (seniorityList.SeniorityListRecords == null) - { - seniorityList.SeniorityListRecords = new List(); - } - - seniorityList.SeniorityListRecords.Add(listRecord); - } + seniorityList.SeniorityListRecords = AddSeniorityListRecord(seniorityList.SeniorityListRecords, listRecord); // sort seniority lists - if (seniorityList.SeniorityListRecords != null) - { - foreach (SeniorityListRecord list in seniorityList.SeniorityListRecords) - { - list.SeniorityList = list.SeniorityList.OrderBy(x => x.SenioritySortOrder).ToList(); - } - } + seniorityList.SeniorityListRecords = SortSeniorityLists(seniorityList.SeniorityListRecords); // classification, print date, type (counterCopy or Year to Date) seniorityList.Classification = $"23010-22/{(fiscalYear - 1).ToString().Substring(2, 2)}-{fiscalYear.ToString().Substring(2, 2)}"; seniorityList.GeneratedOn = $"{DateUtils.ConvertUtcToPacificTime(DateTime.UtcNow):dd-MM-yyyy H:mm:ss}"; - seniorityList.SeniorityListType = counterCopy ? "Counter-Copy" : "Year-to-Date"; + seniorityList.SeniorityListType = GetSeniorityListType(counterCopy); // convert to open xml document - string documentName = $"SeniorityList-{DateTime.Now:yyyy-MM-dd}{(counterCopy ? "-(CounterCopy)" : "")}.docx"; + string documentName = GetDocumentName(counterCopy); byte[] document = SeniorityList.GetSeniorityList(seniorityList, documentName, counterCopy, (errMessage, ex) => { - _logger.LogError(errMessage); - _logger.LogError(ex.ToString()); + _logger.LogError("{errMessage}", errMessage); + _logger.LogError("{exception}", ex.ToString()); }); // return document - FileContentResult result = new FileContentResult(document, "application/vnd.openxmlformats-officedocument.wordprocessingml.document") + FileContentResult result = new(document, "application/vnd.openxmlformats-officedocument.wordprocessingml.document") { FileDownloadName = documentName }; @@ -1519,10 +1548,67 @@ public virtual IActionResult EquipmentSeniorityListDocGet([FromQuery]string loca return result; } - private int GetLastCalledEquipmentId(int localAreaId, int districtEquipmentTypeId, int currentBlock, DateTime fiscalStart) + private static bool IsListRecordDifferent(SeniorityListRecord listRecord, string localAreaName, string districtEquipmentTypeName) + { + return listRecord.LocalAreaName != localAreaName + || listRecord.DistrictEquipmentTypeName != districtEquipmentTypeName; + } + + private static bool IsBlockNumberDifferent(int currentBlock, int? blockNumber) + { + return blockNumber != null && currentBlock != blockNumber; + } + + private static int GetCurrentBlock(int currentBlock, int? blockNumber) + { + return blockNumber ?? currentBlock; + } + + private static string GetListRecordDistrictName(string defaultDistrictName, HetDistrict district) + { + return district != null ? district.Name : defaultDistrictName; + } + + private static List AddSeniorityListRecord( + List records, SeniorityListRecord listRecord) + { + if (!string.IsNullOrEmpty(listRecord.LocalAreaName)) + { + records ??= new List(); + records.Add(listRecord); + } + + return records; + } + + private static List SortSeniorityLists(List records) + { + if (records == null) return records; + + foreach (SeniorityListRecord record in records) + { + record.SeniorityList = record.SeniorityList.OrderBy(x => x.SenioritySortOrder).ToList(); + } + return records; + } + + private static string GetSeniorityListType(bool counterCopy) + { + return counterCopy ? "Counter-Copy" : "Year-to-Date"; + } + + private static string GetDocumentName(bool counterCopy) + { + return $"SeniorityList-{DateTime.Now:yyyy-MM-dd}{(counterCopy ? "-(CounterCopy)" : "")}.docx"; + } + + private int GetLastCalledEquipmentId( + int localAreaId, int districtEquipmentTypeId, int currentBlock, DateTime fiscalStart) { try { + DateTime fiscalStartUtc = DateUtils.AsUTC(fiscalStart); + // HETS-824 = BVT - Corrections to Seniority List PDF // * This column should contain "Y" against the equipment that // last responded (whether Yes/No) in a block @@ -1532,19 +1618,21 @@ private int GetLastCalledEquipmentId(int localAreaId, int districtEquipmentTypeI HetRentalRequestRotationList blockRotation = _context.HetRentalRequestRotationLists.AsNoTracking() .Include(x => x.Equipment) .Include(x => x.RentalRequest) - .OrderByDescending(x => x.RentalRequestId).ThenByDescending(x => x.RotationListSortOrder) - .FirstOrDefault(x => x.RentalRequest.DistrictEquipmentTypeId == districtEquipmentTypeId && - x.RentalRequest.LocalAreaId == localAreaId && - x.RentalRequest.AppCreateTimestamp >= fiscalStart && - x.Equipment.BlockNumber == currentBlock && - x.WasAsked == true && - x.IsForceHire != true); + .OrderByDescending(x => x.RentalRequestId) + .ThenByDescending(x => x.RotationListSortOrder) + .FirstOrDefault(x => + x.RentalRequest.DistrictEquipmentTypeId == districtEquipmentTypeId + && x.RentalRequest.LocalAreaId == localAreaId + && x.RentalRequest.AppCreateTimestamp >= fiscalStartUtc + && x.Equipment.BlockNumber == currentBlock + && x.WasAsked == true + && x.IsForceHire != true); return blockRotation == null ? 0 : (int)blockRotation.EquipmentId; } catch (Exception e) { - _logger.LogError($"GetLastCalledEquipmentId exception: {e.ToString()}"); + _logger.LogError("GetLastCalledEquipmentId exception: {e}", e.ToString()); throw; } } diff --git a/Server/HetsApi/Controllers/OwnerController.cs b/Server/HetsApi/Controllers/OwnerController.cs index e7ea0162d..fc2d5b452 100644 --- a/Server/HetsApi/Controllers/OwnerController.cs +++ b/Server/HetsApi/Controllers/OwnerController.cs @@ -21,6 +21,9 @@ using HetsData.Repositories; using HetsData.Dtos; using AutoMapper; +using HetsCommon; +using DocumentFormat.OpenXml.Spreadsheet; +using DocumentFormat.OpenXml.Drawing.Charts; namespace HetsApi.Controllers { @@ -165,17 +168,22 @@ public virtual ActionResult> OwnersGetLiteTs() // get active status int? statusId = StatusHelper.GetStatusId(HetOwner.StatusApproved, "ownerStatus", _context); - if (statusId == null) return new BadRequestObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusId == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // get fiscal year HetDistrictStatus status = _context.HetDistrictStatuses.AsNoTracking() .First(x => x.DistrictId == districtId); int? fiscalYear = status.CurrentFiscalYear; - if (fiscalYear == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (fiscalYear == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // fiscal year in the status table stores the "start" of the year - DateTime fiscalYearStart = new DateTime((int)fiscalYear, 3, 31); + DateTime fiscalYearStart = DateUtils.ConvertPacificToUtcTime( + new DateTime((int)fiscalYear, 3, 31, 0, 0, 0, DateTimeKind.Unspecified)); // get all active owners for this district (and any projects they're associated with) var owners = _context.HetRentalAgreements.AsNoTracking() @@ -236,10 +244,16 @@ public virtual ActionResult OwnersIdPut([FromRoute]int id, [FromBody]O owner.ConcurrencyControlNumber = item.ConcurrencyControlNumber; owner.CglCompany = item.CglCompany; - owner.CglendDate = item.CglendDate; + if (item.CglendDate is DateTime cglEndDateUtc) + { + owner.CglendDate = DateUtils.AsUTC(cglEndDateUtc); + } owner.CglPolicyNumber = item.CglPolicyNumber; owner.LocalAreaId = item.LocalArea.LocalAreaId; - owner.WorkSafeBcexpiryDate = item.WorkSafeBcexpiryDate; + if (item.WorkSafeBcexpiryDate is DateTime workSafeBcExpiryDateUtc) + { + owner.WorkSafeBcexpiryDate = DateUtils.AsUTC(workSafeBcExpiryDateUtc); + } owner.WorkSafeBcpolicyNumber = item.WorkSafeBcpolicyNumber; owner.IsMaintenanceContractor = item.IsMaintenanceContractor; owner.OrganizationName = item.OrganizationName; @@ -460,21 +474,23 @@ public virtual ActionResult OwnersIdStatusPut([FromRoute]int id, [From public virtual ActionResult OwnersPost([FromBody]OwnerDto item) { // not found - if (item == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (item == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // get status id int? statusId = StatusHelper.GetStatusId(item.Status, "ownerStatus", _context); - if (statusId == null) return new BadRequestObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusId == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // create record - HetOwner owner = new HetOwner + HetOwner owner = new() { OwnerStatusTypeId = (int)statusId, CglCompany = item.CglCompany, - CglendDate = item.CglendDate, CglPolicyNumber = item.CglPolicyNumber, LocalAreaId = item.LocalArea.LocalAreaId, - WorkSafeBcexpiryDate = item.WorkSafeBcexpiryDate, WorkSafeBcpolicyNumber = item.WorkSafeBcpolicyNumber, IsMaintenanceContractor = item.IsMaintenanceContractor ?? false, OrganizationName = item.OrganizationName, @@ -491,6 +507,16 @@ public virtual ActionResult OwnersPost([FromBody]OwnerDto item) MeetsResidency = item.MeetsResidency }; + if (item.CglendDate is DateTime cglEndDateUtc) + { + owner.CglendDate = DateUtils.AsUTC(cglEndDateUtc); + } + + if (item.WorkSafeBcexpiryDate is DateTime workSafeBcExpiryDateUtc) + { + owner.WorkSafeBcexpiryDate = DateUtils.AsUTC(workSafeBcExpiryDateUtc); + } + if (!string.IsNullOrEmpty(item.RegisteredCompanyNumber)) { owner.RegisteredCompanyNumber = item.RegisteredCompanyNumber; @@ -690,7 +716,9 @@ public virtual IActionResult OwnersIdMailingLabelsPdfPost([FromBody]ReportParame // ** Only return Active owner records // get active status int? statusId = StatusHelper.GetStatusId(HetOwner.StatusApproved, "ownerStatus", _context); - if (statusId == null) return new BadRequestObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusId == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // get owner records IQueryable ownerRecords = _context.HetOwners.AsNoTracking() @@ -714,124 +742,129 @@ public virtual IActionResult OwnersIdMailingLabelsPdfPost([FromBody]ReportParame // convert to list List ownerList = ownerRecords.ToList(); - if (ownerList.Any()) - { - // generate pdf document name [unique portion only] - string fileName = "MailingLabels"; + if (!ownerList.Any()) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // record not found - // setup model for submission to the Pdf service - MailingLabelPdfViewModel model = new MailingLabelPdfViewModel - { - ReportDate = DateTime.Now.ToString("yyyy-MM-dd"), - Title = fileName, - DistrictId = ownerList[0].LocalArea.ServiceArea.District.DistrictId, - LabelRow = new List() - }; + // generate pdf document name [unique portion only] + string fileName = "MailingLabels"; - // add owner records - int column = 1; + // setup model for submission to the Pdf service + MailingLabelPdfViewModel model = new() + { + ReportDate = DateTime.Now.ToString("yyyy-MM-dd"), + Title = fileName, + DistrictId = ownerList[0].LocalArea.ServiceArea.District.DistrictId, + LabelRow = new List() + }; - foreach (HetOwner owner in ownerRecords) - { - if (owner.LocalArea.ServiceArea.District == null || - owner.LocalArea.ServiceArea.District.DistrictId != model.DistrictId) - { - // missing district - data error [HETS-16] - return new BadRequestObjectResult(new HetsResponse("HETS-16", ErrorViewModel.GetDescription("HETS-16", _configuration))); - } + // add owner records + int column = 1; - owner.ReportDate = model.ReportDate; - owner.Title = model.Title; - owner.DistrictId = model.DistrictId; + foreach (HetOwner owner in ownerRecords) + { + if (!IsDistrictSame(owner.LocalArea.ServiceArea.District, model.DistrictId)) + { + // missing district - data error [HETS-16] + return new BadRequestObjectResult( + new HetsResponse("HETS-16", ErrorViewModel.GetDescription("HETS-16", _configuration))); + } - switch (column) - { - case 1: - model.LabelRow.Add(new MailingLabelRowModel()); - model.LabelRow.Last().OwnerColumn1 = _mapper.Map(owner); - break; - default: - model.LabelRow.Last().OwnerColumn2 = _mapper.Map(owner); - column = 0; - break; - } + owner.ReportDate = model.ReportDate; + owner.Title = model.Title; + owner.DistrictId = model.DistrictId; - column++; + switch (column) + { + case 1: + model.LabelRow.Add(new MailingLabelRowModel()); + model.LabelRow.Last().OwnerColumn1 = _mapper.Map(owner); + break; + default: + model.LabelRow.Last().OwnerColumn2 = _mapper.Map(owner); + column = 0; + break; } - // setup payload - string payload = JsonConvert.SerializeObject(model, new JsonSerializerSettings - { - ReferenceLoopHandling = ReferenceLoopHandling.Ignore, - ContractResolver = new CamelCasePropertyNamesContractResolver(), - Formatting = Formatting.Indented, - DateFormatHandling = DateFormatHandling.IsoDateFormat, - DateTimeZoneHandling = DateTimeZoneHandling.Utc - }); + column++; + } - _logger.LogInformation("Owner Mailing Labels Pdf - Payload Length: {0}", payload.Length); + // setup payload + string payload = JsonConvert.SerializeObject(model, new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + ContractResolver = new CamelCasePropertyNamesContractResolver(), + Formatting = Newtonsoft.Json.Formatting.Indented, + DateFormatHandling = DateFormatHandling.IsoDateFormat, + DateTimeZoneHandling = DateTimeZoneHandling.Utc + }); - // pass the request on to the Pdf Micro Service - string pdfHost = _configuration["PDF_SERVICE_NAME"]; - string pdfUrl = _configuration.GetSection("Constants:OwnerMailingLabelsPdfUrl").Value; - string targetUrl = pdfHost + pdfUrl; + _logger.LogInformation("Owner Mailing Labels Pdf - Payload Length: {payloadLength}", payload.Length); - targetUrl = targetUrl + "/" + fileName; + // pass the request on to the Pdf Micro Service + string pdfHost = _configuration["PDF_SERVICE_NAME"]; + string pdfUrl = _configuration.GetSection("Constants:OwnerMailingLabelsPdfUrl").Value; + string targetUrl = pdfHost + pdfUrl; - _logger.LogInformation("Owner Mailing Labels Pdf - HETS Pdf Service Url: {0}", targetUrl); + targetUrl = targetUrl + "/" + fileName; - // call the MicroService - try - { - HttpClient client = new HttpClient(); - StringContent stringContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + _logger.LogInformation("Owner Mailing Labels Pdf - HETS Pdf Service Url: {targetUrl}", targetUrl); - _logger.LogInformation("Owner Mailing Labels Pdf - Calling HETS Pdf Service"); - HttpResponseMessage response = client.PostAsync(targetUrl, stringContent).Result; + // call the MicroService + try + { + HttpClient client = new(); + StringContent stringContent = new(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); - // success - if (response.StatusCode == HttpStatusCode.OK) - { - _logger.LogInformation("Owner Mailing Labels Pdf - HETS Pdf Service Response: OK"); + _logger.LogInformation("Owner Mailing Labels Pdf - Calling HETS Pdf Service"); + HttpResponseMessage response = client.PostAsync(targetUrl, stringContent).Result; - var pdfResponseBytes = GetPdf(response, (errMessage, ex) => { - _logger.LogError(errMessage); - _logger.LogError(ex.ToString()); - }); + // success + if (response.StatusCode == HttpStatusCode.OK) + { + _logger.LogInformation("Owner Mailing Labels Pdf - HETS Pdf Service Response: OK"); - // convert to string and log - string pdfResponse = Encoding.Default.GetString(pdfResponseBytes); + var pdfResponseBytes = GetPdf(response, (errMessage, ex) => { + _logger.LogError("{errMessage}", errMessage); + _logger.LogError("{exception}", ex); + }); - fileName = fileName + $"-{DateTime.Now:yyyy-MM-dd-H-mm}" + ".pdf"; + // convert to string and log + string pdfResponse = Encoding.Default.GetString(pdfResponseBytes); - _logger.LogInformation("Owner Mailing Labels Pdf - HETS Pdf Filename: {0}", fileName); - _logger.LogInformation("Owner Mailing Labels Pdf - HETS Pdf Size: {0}", pdfResponse.Length); + fileName = fileName + $"-{DateTime.Now:yyyy-MM-dd-H-mm}" + ".pdf"; - // return content - FileContentResult result = new FileContentResult(pdfResponseBytes, "application/pdf") - { - FileDownloadName = fileName - }; + _logger.LogInformation("Owner Mailing Labels Pdf - HETS Pdf Filename: {fileName}", fileName); + _logger.LogInformation("Owner Mailing Labels Pdf - HETS Pdf Size: {pdfResponseLength}", pdfResponse.Length); - Response.Headers.Add("Content-Disposition", "inline; filename=" + fileName); + // return content + FileContentResult result = new(pdfResponseBytes, "application/pdf") + { + FileDownloadName = fileName + }; - return result; - } + Response.Headers.Add("Content-Disposition", "inline; filename=" + fileName); - _logger.LogInformation("Owner Mailing Labels Pdf - HETS Pdf Service Response: {0}", response.StatusCode); - } - catch (Exception ex) - { - Debug.Write("Error generating pdf: " + ex.Message); - return new BadRequestObjectResult(new HetsResponse("HETS-15", ErrorViewModel.GetDescription("HETS-15", _configuration))); + return result; } - // problem occured - return new BadRequestObjectResult(new HetsResponse("HETS-15", ErrorViewModel.GetDescription("HETS-15", _configuration))); + _logger.LogInformation("Owner Mailing Labels Pdf - HETS Pdf Service Response: {statusCode}", response.StatusCode); + } + catch (Exception ex) + { + Debug.Write("Error generating pdf: " + ex.Message); + return new BadRequestObjectResult( + new HetsResponse("HETS-15", ErrorViewModel.GetDescription("HETS-15", _configuration))); } - // record not found - return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + // problem occured + return new BadRequestObjectResult( + new HetsResponse("HETS-15", ErrorViewModel.GetDescription("HETS-15", _configuration))); + } + + private static bool IsDistrictSame(HetDistrict district, int districtId) + { + return district is not null && district.DistrictId == districtId; } private static byte[] GetPdf(HttpResponseMessage response, Action logErrorAction) @@ -883,7 +916,8 @@ public virtual IActionResult OwnersIdMailingLabelsDocPost([FromBody]ReportParame if (!owners.Any()) { - return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); } var fileName = $"MailingLabels-{DateTime.Now:yyyy-MM-dd-H-mm}.docx"; @@ -892,7 +926,7 @@ public virtual IActionResult OwnersIdMailingLabelsDocPost([FromBody]ReportParame _logger.LogError(ex.ToString()); }); - FileContentResult result = new FileContentResult(file, "application/vnd.openxmlformats-officedocument.wordprocessingml.document") + FileContentResult result = new(file, "application/vnd.openxmlformats-officedocument.wordprocessingml.document") { FileDownloadName = fileName }; @@ -956,12 +990,16 @@ public virtual ActionResult> OwnersIdEquipmentGet([FromRoute] [HttpPut] [Route("{id}/equipment")] [RequiresPermission(HetPermission.Login, HetPermission.WriteAccess)] - public virtual ActionResult> OwnersIdEquipmentPut([FromRoute]int id, [FromBody]EquipmentDto[] items) + public virtual ActionResult> OwnersIdEquipmentPut( + [FromRoute]int id, + [FromBody]EquipmentDto[] items) { bool exists = _context.HetOwners.Any(a => a.OwnerId == id); // not found - if (!exists || items == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists || items == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); var entities = new List(); @@ -972,7 +1010,7 @@ public virtual ActionResult> OwnersIdEquipmentPut([FromRoute] if (item != null) { - DateTime lastVerifiedDate = item.LastVerifiedDate; + DateTime lastVerifiedDate = DateUtils.AsUTC(item.LastVerifiedDate); bool equipmentExists = _context.HetEquipments .Any(x => x.EquipmentId == item.EquipmentId && item.OwnerId == id); @@ -1012,28 +1050,41 @@ public virtual ActionResult> OwnersIdEquipmentPut([FromRoute] [HttpPost] [Route("{id}/equipmentTransfer/{targetOwnerId}/{includeSeniority}")] [RequiresPermission(HetPermission.Login, HetPermission.WriteAccess)] - public virtual ActionResult> OwnersIdEquipmentTransferPost([FromRoute]int id, [FromRoute]int targetOwnerId, - [FromRoute]bool includeSeniority, [FromBody]EquipmentDto[] items) + public virtual ActionResult> OwnersIdEquipmentTransferPost( + [FromRoute]int id, + [FromRoute]int targetOwnerId, + [FromRoute]bool includeSeniority, + [FromBody]EquipmentDto[] items) { bool ownerExists = _context.HetOwners.Any(a => a.OwnerId == id); bool targetOwnerExists = _context.HetOwners.Any(a => a.OwnerId == targetOwnerId); // not found - if (!ownerExists || !targetOwnerExists || items == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (OwnerOrEquipmentNotFound(ownerExists, targetOwnerExists, items)) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); - if (id == targetOwnerId) return new BadRequestObjectResult(new HetsResponse("HETS-34", ErrorViewModel.GetDescription("HETS-34", _configuration))); + if (id == targetOwnerId) + return new BadRequestObjectResult( + new HetsResponse("HETS-34", ErrorViewModel.GetDescription("HETS-34", _configuration))); // get active owner status type int? ownerStatusId = StatusHelper.GetStatusId(HetOwner.StatusApproved, "ownerStatus", _context); - if (ownerStatusId == null) return new NotFoundObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (ownerStatusId == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // get active equipment status type int? equipmentStatusId = StatusHelper.GetStatusId(HetEquipment.StatusApproved, "equipmentStatus", _context); - if (equipmentStatusId == null) return new NotFoundObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (equipmentStatusId == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // get archive equipment status type int? equipmentArchiveStatusId = StatusHelper.GetStatusId(HetEquipment.StatusArchived, "equipmentStatus", _context); - if (equipmentArchiveStatusId == null) return new NotFoundObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (equipmentArchiveStatusId == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); //*************************************************************** // HETS-706: BVT Bulk Transfer @@ -1069,17 +1120,17 @@ public virtual ActionResult> OwnersIdEquipmentTransferPost([F .First(a => a.OwnerId == targetOwnerId); // check they are in the same district - if (currentOwner.LocalArea.ServiceArea.District.DistrictId != - targetOwner.LocalArea.ServiceArea.District.DistrictId) + if (OwnersInDifferentDistricts(currentOwner, targetOwner)) { - return new BadRequestObjectResult(new HetsResponse("HETS-31", ErrorViewModel.GetDescription("HETS-31", _configuration))); + return new BadRequestObjectResult( + new HetsResponse("HETS-31", ErrorViewModel.GetDescription("HETS-31", _configuration))); } // check they are both active - if (currentOwner.OwnerStatusTypeId != ownerStatusId || - targetOwner.OwnerStatusTypeId != ownerStatusId) + if (OwnersNotActive(currentOwner, targetOwner, ownerStatusId)) { - return new BadRequestObjectResult(new HetsResponse("HETS-32", ErrorViewModel.GetDescription("HETS-32", _configuration))); + return new BadRequestObjectResult( + new HetsResponse("HETS-32", ErrorViewModel.GetDescription("HETS-32", _configuration))); } var equipmentsToTransfer = new List(); @@ -1092,9 +1143,10 @@ public virtual ActionResult> OwnersIdEquipmentTransferPost([F .Include(x => x.HetEquipmentAttachments) .FirstOrDefault(x => x.EquipmentId == item.EquipmentId); - if (equipmentToTransfer == null || equipmentToTransfer.OwnerId != currentOwner.OwnerId) + if (EquipmentDoesntBelongToOwner(equipmentToTransfer, currentOwner)) { - return new BadRequestObjectResult(new HetsResponse("HETS-33", ErrorViewModel.GetDescription("HETS-33", _configuration))); + return new BadRequestObjectResult( + new HetsResponse("HETS-33", ErrorViewModel.GetDescription("HETS-33", _configuration))); } equipmentsToTransfer.Add(equipmentToTransfer); @@ -1106,10 +1158,13 @@ public virtual ActionResult> OwnersIdEquipmentTransferPost([F HetDistrictStatus district = _context.HetDistrictStatuses.AsNoTracking() .FirstOrDefault(x => x.DistrictId == currentOwner.LocalArea.ServiceArea.District.DistrictId); - if (district?.CurrentFiscalYear == null) return new NotFoundObjectResult(new HetsResponse("HETS-30", ErrorViewModel.GetDescription("HETS-30", _configuration))); + if (district?.CurrentFiscalYear == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-30", ErrorViewModel.GetDescription("HETS-30", _configuration))); int fiscalYear = (int)district.CurrentFiscalYear; // status table uses the start of the year - DateTime fiscalStart = new DateTime(fiscalYear, 4, 1); + DateTime fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(fiscalYear, 4, 1, 0, 0, 0, DateTimeKind.Unspecified)); //*************************************************************** // process each piece of equipment in the provided list @@ -1124,7 +1179,7 @@ public virtual ActionResult> OwnersIdEquipmentTransferPost([F string newEquipmentCode = EquipmentHelper.GetEquipmentCode(targetOwner.OwnerId, _context); // create a "copy" of the record - HetEquipment newEquipment = new HetEquipment + HetEquipment newEquipment = new() { OwnerId = targetOwnerId, LocalAreaId = equipmentToTransfer.LocalAreaId, @@ -1135,7 +1190,6 @@ public virtual ActionResult> OwnersIdEquipmentTransferPost([F Make = equipmentToTransfer.Make, Model = equipmentToTransfer.Model, Operator = equipmentToTransfer.Operator, - ReceivedDate = equipmentToTransfer.ReceivedDate, LicencePlate = equipmentToTransfer.LicencePlate, SerialNumber = equipmentToTransfer.SerialNumber, Size = equipmentToTransfer.Size, @@ -1143,7 +1197,7 @@ public virtual ActionResult> OwnersIdEquipmentTransferPost([F RefuseRate = equipmentToTransfer.RefuseRate, YearsOfService = 0, Year = equipmentToTransfer.Year, - LastVerifiedDate = equipmentToTransfer.LastVerifiedDate, + LastVerifiedDate = DateUtils.AsUTC(equipmentToTransfer.LastVerifiedDate), IsSeniorityOverridden = false, SeniorityOverrideReason = "", Type = equipmentToTransfer.Type, @@ -1156,34 +1210,18 @@ public virtual ActionResult> OwnersIdEquipmentTransferPost([F PupLegalCapacity = equipmentToTransfer.PupLegalCapacity }; - foreach (HetEquipmentAttachment attachment in equipmentToTransfer.HetEquipmentAttachments) + if (equipmentToTransfer.ReceivedDate is DateTime receivedDateUtc) { - if (newEquipment.HetEquipmentAttachments == null) - { - newEquipment.HetEquipmentAttachments = new List(); - } - - HetEquipmentAttachment newAttachment = new HetEquipmentAttachment - { - Description = attachment.TypeName, - TypeName = attachment.TypeName - }; - - newEquipment.HetEquipmentAttachments.Add(newAttachment); + newEquipment.ReceivedDate = DateUtils.AsUTC(receivedDateUtc); } + newEquipment.HetEquipmentAttachments = + GetEquipmentAttachments(newEquipment.HetEquipmentAttachments, equipmentToTransfer); + // seniority information: // YTD / YTD1 / YTD2 / YTD3 / YTD3 / // Years Registered / Seniority - if (includeSeniority) - { - newEquipment.ServiceHoursLastYear = equipmentToTransfer.ServiceHoursLastYear; - newEquipment.ServiceHoursTwoYearsAgo = equipmentToTransfer.ServiceHoursTwoYearsAgo; - newEquipment.ServiceHoursThreeYearsAgo = equipmentToTransfer.ServiceHoursThreeYearsAgo; - newEquipment.YearsOfService = equipmentToTransfer.YearsOfService; - newEquipment.Seniority = equipmentToTransfer.Seniority; - newEquipment.ApprovedDate = equipmentToTransfer.ApprovedDate; - } + newEquipment = IncludeSeniorityWithEquipment(includeSeniority, newEquipment, equipmentToTransfer); _context.HetEquipments.Add(newEquipment); @@ -1193,23 +1231,9 @@ public virtual ActionResult> OwnersIdEquipmentTransferPost([F equipmentToTransfer.ArchiveDate = DateTime.UtcNow; equipmentToTransfer.ArchiveReason = "Bulk transfer to " + targetOwner.OwnerCode; - _context.SaveChanges(); //this ensures newEquipment.EquimentId is assigned. - - if (includeSeniority) - { - int newEquipmentId = newEquipment.EquipmentId; + _context.SaveChanges(); // this ensures newEquipment.EquimentId is assigned. - // we also need to update all of the associated rental agreements - // (for this fiscal year) - IQueryable agreements = _context.HetRentalAgreements - .Where(x => x.EquipmentId == equipmentToTransfer.EquipmentId && - x.DatedOn >= fiscalStart); - - foreach (HetRentalAgreement agreement in agreements) - { - agreement.EquipmentId = newEquipmentId; - } - } + UpdateRentalAgreements(includeSeniority, newEquipment.EquipmentId, equipmentToTransfer, fiscalStart); _context.SaveChanges(); } @@ -1218,7 +1242,43 @@ public virtual ActionResult> OwnersIdEquipmentTransferPost([F // we need to update seniority for all local areas and // district equipment types //*************************************************************** - List districtEquipmentTypes = new List(); + equipmentsToTransfer = UpdateSeniorityForEquipmentTypes(equipmentsToTransfer); + + _context.SaveChanges(); + + transaction.Commit(); + + // return original items + return new ObjectResult( + new HetsResponse( + _mapper.Map>(equipmentsToTransfer))); + } + + private static bool EquipmentDoesntBelongToOwner(HetEquipment equipmentToTransfer, HetOwner currentOwner) + { + return equipmentToTransfer == null || equipmentToTransfer.OwnerId != currentOwner.OwnerId; + } + + private static bool OwnerOrEquipmentNotFound(bool ownerExists, bool targetOwnerExists, EquipmentDto[] items) + { + return !ownerExists || !targetOwnerExists || items == null; + } + + private static bool OwnersInDifferentDistricts(HetOwner currentOwner, HetOwner targetOwner) + { + return currentOwner.LocalArea.ServiceArea.District.DistrictId + != targetOwner.LocalArea.ServiceArea.District.DistrictId; + } + + private static bool OwnersNotActive(HetOwner currentOwner, HetOwner targetOwner, int? ownerStatusId) + { + return currentOwner.OwnerStatusTypeId != ownerStatusId + || targetOwner.OwnerStatusTypeId != ownerStatusId; + } + + private List UpdateSeniorityForEquipmentTypes(List equipmentsToTransfer) + { + List districtEquipmentTypes = new(); foreach (var equipmentToTransfer in equipmentsToTransfer) { @@ -1236,18 +1296,68 @@ public virtual ActionResult> OwnersIdEquipmentTransferPost([F // recalculate seniority EquipmentHelper.RecalculateSeniority(localAreaId, districtEquipmentTypeId, _context, _configuration, (errMessage, ex) => { - _logger.LogError(errMessage); - _logger.LogError(ex.ToString()); + _logger.LogError("{errMessage}", errMessage); + _logger.LogError("{exception}", ex); }); } } - _context.SaveChanges(); + return equipmentsToTransfer; + } - transaction.Commit(); + private static ICollection GetEquipmentAttachments( + ICollection existingAttachments, HetEquipment equipmentToTransfer) + { + var attachments = existingAttachments ?? new List(); + var newAttachments = equipmentToTransfer.HetEquipmentAttachments + .Select(attachment => new HetEquipmentAttachment + { + Description = attachment.TypeName, + TypeName = attachment.TypeName + }); - // return original items - return new ObjectResult(new HetsResponse(_mapper.Map>(equipmentsToTransfer))); + foreach (HetEquipmentAttachment attachment in newAttachments) + { + attachments.Add(attachment); + } + return attachments; + } + + private static HetEquipment IncludeSeniorityWithEquipment( + bool includeSeniority, HetEquipment newEquipment, HetEquipment equipmentToTransfer) + { + if (includeSeniority) + { + newEquipment.ServiceHoursLastYear = equipmentToTransfer.ServiceHoursLastYear; + newEquipment.ServiceHoursTwoYearsAgo = equipmentToTransfer.ServiceHoursTwoYearsAgo; + newEquipment.ServiceHoursThreeYearsAgo = equipmentToTransfer.ServiceHoursThreeYearsAgo; + newEquipment.YearsOfService = equipmentToTransfer.YearsOfService; + newEquipment.Seniority = equipmentToTransfer.Seniority; + if (equipmentToTransfer.ApprovedDate is DateTime approvedDateUtc) + { + newEquipment.ApprovedDate = DateUtils.AsUTC(approvedDateUtc); + } + } + return newEquipment; + } + + private void UpdateRentalAgreements( + bool includeSeniority, int newEquipmentId, HetEquipment equipmentToTransfer, DateTime fiscalStart) + { + if (!includeSeniority) return; + + // we also need to update all of the associated rental agreements + // (for this fiscal year) + DateTime fiscalStartUtc = DateUtils.AsUTC(fiscalStart); + + IQueryable agreements = _context.HetRentalAgreements + .Where(x => x.EquipmentId == equipmentToTransfer.EquipmentId && + x.DatedOn >= fiscalStartUtc); + + foreach (HetRentalAgreement agreement in agreements) + { + agreement.EquipmentId = newEquipmentId; + } } #endregion @@ -1281,7 +1391,7 @@ public virtual ActionResult> OwnersIdAttachmentsGet([FromRo if (attachment != null) { attachment.FileSize = attachment.FileContents.Length; - attachment.LastUpdateTimestamp = attachment.AppLastUpdateTimestamp; + attachment.LastUpdateTimestamp = DateUtils.AsUTC(attachment.AppLastUpdateTimestamp); attachment.LastUpdateUserid = attachment.AppLastUpdateUserid; attachment.UserName = UserHelper.GetUserName(attachment.LastUpdateUserid, _context); attachments.Add(attachment); @@ -1555,7 +1665,7 @@ public virtual ActionResult> OwnersIdHistoryPost([FromRoute]int id if (exists) { - HetHistory history = new HetHistory + HetHistory history = new() { HistoryId = 0, HistoryText = item.HistoryText, @@ -1787,26 +1897,43 @@ public virtual IActionResult GenerateKeysApiPost() [HttpGet] [Route("wcbCglReport")] [RequiresPermission(HetPermission.Login)] - public virtual ActionResult> OwnerWcbCglGet([FromQuery]string localAreas, [FromQuery]string owners, - [FromQuery]DateTime? wcbExpiry, [FromQuery]DateTime? cglExpiry) + public virtual ActionResult> OwnerWcbCglGet( + [FromQuery]string localAreas, + [FromQuery]string owners, + [FromQuery]DateTime? wcbExpiry, + [FromQuery]DateTime? cglExpiry) { int?[] localAreasArray = ArrayHelper.ParseIntArray(localAreas); int?[] ownerArray = ArrayHelper.ParseIntArray(owners); // owner status int? statusId = StatusHelper.GetStatusId(HetOwner.StatusApproved, "ownerStatus", _context); - if (statusId == null) return new BadRequestObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusId == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // get initial results - must be limited to user's district int? districtId = UserAccountHelper.GetUsersDistrictId(_context); + DateTime? wcbExpiryUTC = wcbExpiry is DateTime wcbExpiryDt ? DateUtils.AsUTC(wcbExpiryDt) : null; + DateTime? cglExpiryUTC = cglExpiry is DateTime cglExpiryDt ? DateUtils.AsUTC(cglExpiryDt) : null; + IQueryable data = _context.HetOwners.AsNoTracking() .Include(y => y.LocalArea.ServiceArea) .Include(x => x.PrimaryContact) - .Where(x => x.LocalArea.ServiceArea.DistrictId.Equals(districtId) && - x.OwnerStatusTypeId == statusId && - (x.WorkSafeBcexpiryDate == null || wcbExpiry == null || x.WorkSafeBcexpiryDate < wcbExpiry) && - (x.CglendDate == null || cglExpiry == null || x.CglendDate < cglExpiry)); + .Where(x => + x.LocalArea.ServiceArea.DistrictId.Equals(districtId) + && x.OwnerStatusTypeId == statusId + && ( + x.WorkSafeBcexpiryDate == null + || wcbExpiry == null + || wcbExpiryUTC == null + || x.WorkSafeBcexpiryDate < wcbExpiryUTC) + && ( + x.CglendDate == null + || cglExpiry == null + || cglExpiryUTC == null + || x.CglendDate < cglExpiryUTC)); if (localAreasArray != null && localAreasArray.Length > 0) { @@ -1819,7 +1946,7 @@ public virtual ActionResult> OwnerWcbCglGet([FromQuery]string } // convert Rental Request Model to the "RentalRequestHires" Model - List result = new List(); + List result = new(); foreach (HetOwner item in data) { diff --git a/Server/HetsApi/Controllers/ProjectController.cs b/Server/HetsApi/Controllers/ProjectController.cs index 6059a0885..5da2bbadc 100644 --- a/Server/HetsApi/Controllers/ProjectController.cs +++ b/Server/HetsApi/Controllers/ProjectController.cs @@ -13,6 +13,7 @@ using HetsData.Repositories; using HetsData.Dtos; using AutoMapper; +using HetsCommon; namespace HetsApi.Controllers { @@ -566,10 +567,13 @@ public virtual ActionResult> HetProjectIdTimeRecordsGet([Fro .First(x => x.DistrictId == districtId); int? fiscalYear = status.CurrentFiscalYear; - if (fiscalYear == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (fiscalYear == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // fiscal year in the status table stores the "start" of the year - DateTime fiscalYearStart = new DateTime((int)fiscalYear, 4, 1); + DateTime fiscalYearStart = DateUtils.ConvertPacificToUtcTime( + new DateTime((int)fiscalYear, 4, 1, 0, 0, 0, DateTimeKind.Unspecified)); HetProject project = _context.HetProjects.AsNoTracking() .Include(x => x.HetRentalAgreements) @@ -577,7 +581,7 @@ public virtual ActionResult> HetProjectIdTimeRecordsGet([Fro .First(x => x.ProjectId == id); // create a single array of all time records - List timeRecords = new List(); + List timeRecords = new(); foreach (HetRentalAgreement rentalAgreement in project.HetRentalAgreements) { @@ -635,8 +639,8 @@ public virtual ActionResult> ProjectsIdTimeRecordsPost([From int rentalAgreementId = (int)item.RentalAgreementId; // set the time period type id - int? timePeriodTypeId = StatusHelper.GetTimePeriodId(item.TimePeriod, _context); - if (timePeriodTypeId == null) throw new DataException("Time Period Id cannot be null"); + int? timePeriodTypeId = StatusHelper.GetTimePeriodId(item.TimePeriod, _context) + ?? throw new DataException("Time Period Id cannot be null"); if (item.TimeRecordId > 0) { @@ -644,7 +648,9 @@ public virtual ActionResult> ProjectsIdTimeRecordsPost([From HetTimeRecord time = _context.HetTimeRecords.FirstOrDefault(x => x.TimeRecordId == item.TimeRecordId); // not found - if (time == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (time == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); time.ConcurrencyControlNumber = item.ConcurrencyControlNumber; time.RentalAgreementId = rentalAgreementId; @@ -652,18 +658,18 @@ public virtual ActionResult> ProjectsIdTimeRecordsPost([From time.Hours = item.Hours; time.TimePeriod = item.TimePeriod; time.TimePeriodTypeId = (int)timePeriodTypeId; - time.WorkedDate = item.WorkedDate; + time.WorkedDate = DateUtils.AsUTC(item.WorkedDate); } else // add time record { - HetTimeRecord time = new HetTimeRecord + HetTimeRecord time = new() { RentalAgreementId = rentalAgreementId, EnteredDate = DateTime.UtcNow, Hours = item.Hours, TimePeriod = item.TimePeriod, TimePeriodTypeId = (int)timePeriodTypeId, - WorkedDate = item.WorkedDate + WorkedDate = DateUtils.AsUTC(item.WorkedDate) }; _context.HetTimeRecords.Add(time); @@ -681,14 +687,15 @@ public virtual ActionResult> ProjectsIdTimeRecordsPost([From .First(x => x.ProjectId == id); // create a single array of all time records - List timeRecords = new List(); + List timeRecords = new(); foreach (HetRentalAgreement rentalAgreement in project.HetRentalAgreements) { timeRecords.AddRange(rentalAgreement.HetTimeRecords); } - return new ObjectResult(new HetsResponse(_mapper.Map>(timeRecords))); + return new ObjectResult( + new HetsResponse(_mapper.Map>(timeRecords))); } #endregion @@ -736,28 +743,31 @@ public virtual ActionResult> ProjectsIdAttachmentsGet([From bool exists = _context.HetProjects.Any(a => a.ProjectId == id); // not found - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); HetProject project = _context.HetProjects.AsNoTracking() .Include(x => x.HetDigitalFiles) .First(a => a.ProjectId == id); // extract the attachments and update properties for UI - List attachments = new List(); + List attachments = new(); foreach (HetDigitalFile attachment in project.HetDigitalFiles) { if (attachment != null) { attachment.FileSize = attachment.FileContents.Length; - attachment.LastUpdateTimestamp = attachment.AppLastUpdateTimestamp; + attachment.LastUpdateTimestamp = DateUtils.AsUTC(attachment.AppLastUpdateTimestamp); attachment.LastUpdateUserid = attachment.AppLastUpdateUserid; attachment.UserName = UserHelper.GetUserName(attachment.LastUpdateUserid, _context); attachments.Add(attachment); } } - return new ObjectResult(new HetsResponse(_mapper.Map>(attachments))); + return new ObjectResult( + new HetsResponse(_mapper.Map>(attachments))); } #endregion @@ -1012,13 +1022,15 @@ public virtual ActionResult> ProjectsIdHistoryGet([FromRoute] int [HttpPost] [Route("{id}/history")] [RequiresPermission(HetPermission.Login, HetPermission.WriteAccess)] - public virtual ActionResult ProjectsIdHistoryPost([FromRoute] int id, [FromBody] History item) + public virtual ActionResult ProjectsIdHistoryPost( + [FromRoute] int id, + [FromBody] History item) { bool exists = _context.HetProjects.Any(a => a.ProjectId == id); if (exists) { - HetHistory history = new HetHistory + HetHistory history = new() { HistoryText = item.HistoryText, CreatedDate = DateTime.UtcNow, @@ -1029,7 +1041,8 @@ public virtual ActionResult ProjectsIdHistoryPost([FromRoute] int id, [ _context.SaveChanges(); } - return new ObjectResult(new HetsResponse(ProjectHelper.GetHistoryRecords(id, null, null, _context))); + return new ObjectResult( + new HetsResponse(ProjectHelper.GetHistoryRecords(id, null, null, _context))); } #endregion diff --git a/Server/HetsApi/Controllers/RentalAgreementController.cs b/Server/HetsApi/Controllers/RentalAgreementController.cs index 5673fc326..4cc72f5f5 100644 --- a/Server/HetsApi/Controllers/RentalAgreementController.cs +++ b/Server/HetsApi/Controllers/RentalAgreementController.cs @@ -17,6 +17,7 @@ using HetsData.Dtos; using HetsData.Repositories; using AutoMapper; +using HetsCommon; namespace HetsApi.Controllers { @@ -73,13 +74,16 @@ public virtual ActionResult RentalAgreementsIdPut([FromRoute if (item == null || id != item.RentalAgreementId) { // not found - return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); } bool exists = _context.HetRentalAgreements.Any(a => a.RentalAgreementId == id); // not found - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // get record HetRentalAgreement agreement = _context.HetRentalAgreements @@ -87,7 +91,9 @@ public virtual ActionResult RentalAgreementsIdPut([FromRoute .First(a => a.RentalAgreementId == id); int? statusId = StatusHelper.GetStatusId(item.Status, "rentalAgreementStatus", _context); - if (statusId == null) return new BadRequestObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusId == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // get overtime records List overtime = _context.HetProvincialRateTypes.AsNoTracking() @@ -95,12 +101,8 @@ public virtual ActionResult RentalAgreementsIdPut([FromRoute .ToList(); // get rate period type for the agreement - int? rateTypeId = StatusHelper.GetRatePeriodId(item.RatePeriod, _context); - - if (rateTypeId == null) - { - throw new DataException("Rate Period Id cannot be null"); - } + int? rateTypeId = StatusHelper.GetRatePeriodId(item.RatePeriod, _context) + ?? throw new DataException("Rate Period Id cannot be null"); string city = item.AgreementCity; @@ -111,7 +113,9 @@ public virtual ActionResult RentalAgreementsIdPut([FromRoute // update the agreement record agreement.ConcurrencyControlNumber = item.ConcurrencyControlNumber; - agreement.DatedOn = item.DatedOn; + if (item.DatedOn is DateTime datedOnUtc) { + agreement.DatedOn = DateUtils.AsUTC(datedOnUtc); + } agreement.AgreementCity = city; agreement.EquipmentRate = item.EquipmentRate; agreement.EstimateHours = item.EstimateHours; @@ -203,15 +207,13 @@ public virtual ActionResult RentalAgreementsIdPut([FromRoute public virtual ActionResult RentalAgreementsPost([FromBody] RentalAgreementDto item) { // not found - if (item == null) return new BadRequestObjectResult(new HetsResponse("HETS-04", ErrorViewModel.GetDescription("HETS-04", _configuration))); + if (item == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-04", ErrorViewModel.GetDescription("HETS-04", _configuration))); // set the rate period type id - int? rateTypeId = StatusHelper.GetRatePeriodId(item.RatePeriod, _context); - - if (rateTypeId == null) - { - throw new DataException("Rate Period Id cannot be null"); - } + int? rateTypeId = StatusHelper.GetRatePeriodId(item.RatePeriod, _context) + ?? throw new DataException("Rate Period Id cannot be null"); // get overtime records List overtime = _context.HetProvincialRateTypes.AsNoTracking() @@ -220,17 +222,18 @@ public virtual ActionResult RentalAgreementsPost([FromBody] // get status for new agreement int? statusId = StatusHelper.GetStatusId(item.Status, "rentalAgreementStatus", _context); - if (statusId == null) return new BadRequestObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusId == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // get user info - agreement city CurrentUserDto user = UserAccountHelper.GetUser(_context, _httpContext); string agreementCity = user.AgreementCity; // create agreement - HetRentalAgreement agreement = new HetRentalAgreement + HetRentalAgreement agreement = new() { Number = RentalAgreementHelper.GetRentalAgreementNumber(item.Equipment?.LocalAreaId, _context), - DatedOn = item.DatedOn, AgreementCity = agreementCity, EquipmentRate = item.EquipmentRate, EstimateHours = item.EstimateHours, @@ -243,6 +246,11 @@ public virtual ActionResult RentalAgreementsPost([FromBody] ProjectId = item.ProjectId }; + if (item.DatedOn is DateTime datedOnUtc) + { + agreement.DatedOn = DateUtils.AsUTC(datedOnUtc); + } + // agreement overtime records (default overtime flag) if (item.OvertimeRates != null) { @@ -412,18 +420,22 @@ private static string CleanName(string name) [HttpGet] [Route("{id}/timeRecords")] [RequiresPermission(HetPermission.Login)] - public virtual ActionResult RentalAgreementsIdTimeRecordsGet([FromRoute] int id) + public virtual ActionResult RentalAgreementsIdTimeRecordsGet( + [FromRoute] int id) { bool exists = _context.HetRentalAgreements.Any(a => a.RentalAgreementId == id); // not found - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // get current district int? districtId = UserAccountHelper.GetUsersDistrictId(_context); // return time records - return new ObjectResult(new HetsResponse(_rentalAgreementRepo.GetTimeRecords(id, districtId))); + return new ObjectResult( + new HetsResponse(_rentalAgreementRepo.GetTimeRecords(id, districtId))); } /// @@ -435,7 +447,9 @@ public virtual ActionResult RentalAgreementsIdTimeRecordsGet([Fr [HttpPost] [Route("{id}/timeRecord")] [RequiresPermission(HetPermission.Login, HetPermission.WriteAccess)] - public virtual ActionResult RentalAgreementsIdTimeRecordsPost([FromRoute] int id, [FromBody] TimeRecordDto item) + public virtual ActionResult RentalAgreementsIdTimeRecordsPost( + [FromRoute] int id, + [FromBody] TimeRecordDto item) { bool exists = _context.HetRentalAgreements.Any(a => a.RentalAgreementId == id); @@ -444,8 +458,8 @@ public virtual ActionResult RentalAgreementsIdTimeRecordsPost([F return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // set the time period type id - int? timePeriodTypeId = StatusHelper.GetTimePeriodId(item.TimePeriod, _context); - if (timePeriodTypeId == null) throw new DataException("Time Period Id cannot be null"); + int? timePeriodTypeId = StatusHelper.GetTimePeriodId(item.TimePeriod, _context) + ?? throw new DataException("Time Period Id cannot be null"); // get current district int? districtId = UserAccountHelper.GetUsersDistrictId(_context); @@ -457,25 +471,27 @@ public virtual ActionResult RentalAgreementsIdTimeRecordsPost([F HetTimeRecord time = _context.HetTimeRecords.First(a => a.TimeRecordId == item.TimeRecordId); // not found - if (time == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (time == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); time.ConcurrencyControlNumber = item.ConcurrencyControlNumber; time.EnteredDate = DateTime.UtcNow; time.Hours = item.Hours; time.TimePeriod = item.TimePeriod; time.TimePeriodTypeId = (int)timePeriodTypeId; - time.WorkedDate = item.WorkedDate; + time.WorkedDate = DateUtils.AsUTC(item.WorkedDate); } else // add time record { - HetTimeRecord time = new HetTimeRecord + HetTimeRecord time = new() { RentalAgreementId = id, EnteredDate = DateTime.UtcNow, Hours = item.Hours, TimePeriod = item.TimePeriod, TimePeriodTypeId = (int)timePeriodTypeId, - WorkedDate = item.WorkedDate + WorkedDate = DateUtils.AsUTC(item.WorkedDate) }; _context.HetTimeRecords.Add(time); @@ -484,7 +500,8 @@ public virtual ActionResult RentalAgreementsIdTimeRecordsPost([F _context.SaveChanges(); // retrieve updated time records to return to ui - return new ObjectResult(new HetsResponse(_rentalAgreementRepo.GetTimeRecords(id, districtId))); + return new ObjectResult( + new HetsResponse(_rentalAgreementRepo.GetTimeRecords(id, districtId))); } /// @@ -496,12 +513,16 @@ public virtual ActionResult RentalAgreementsIdTimeRecordsPost([F [HttpPost] [Route("{id}/timeRecords")] [RequiresPermission(HetPermission.Login, HetPermission.WriteAccess)] - public virtual ActionResult RentalAgreementsIdTimeRecordsBulkPostAsync([FromRoute] int id, [FromBody] TimeRecordDto[] items) + public virtual ActionResult RentalAgreementsIdTimeRecordsBulkPostAsync( + [FromRoute] int id, + [FromBody] TimeRecordDto[] items) { bool exists = _context.HetRentalAgreements.Any(a => a.RentalAgreementId == id); // not found - if (!exists || items == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists || items == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // get current district int? districtId = UserAccountHelper.GetUsersDistrictId(_context); @@ -510,8 +531,8 @@ public virtual ActionResult RentalAgreementsIdTimeRecordsBulkPos foreach (var item in items) { // set the time period type id - int? timePeriodTypeId = StatusHelper.GetTimePeriodId(item.TimePeriod, _context); - if (timePeriodTypeId == null) throw new DataException("Time Period Id cannot be null"); + int? timePeriodTypeId = StatusHelper.GetTimePeriodId(item.TimePeriod, _context) + ?? throw new DataException("Time Period Id cannot be null"); // add or update time record if (item.TimeRecordId > 0) @@ -520,25 +541,27 @@ public virtual ActionResult RentalAgreementsIdTimeRecordsBulkPos HetTimeRecord time = _context.HetTimeRecords.First(a => a.TimeRecordId == item.TimeRecordId); // not found - if (time == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (time == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); time.ConcurrencyControlNumber = item.ConcurrencyControlNumber; time.EnteredDate = DateTime.UtcNow; time.Hours = item.Hours; time.TimePeriod = item.TimePeriod; time.TimePeriodTypeId = (int)timePeriodTypeId; - time.WorkedDate = item.WorkedDate; + time.WorkedDate = DateUtils.AsUTC(item.WorkedDate); } else // add time record { - HetTimeRecord time = new HetTimeRecord + HetTimeRecord time = new() { RentalAgreementId = id, EnteredDate = DateTime.UtcNow, Hours = item.Hours, TimePeriod = item.TimePeriod, TimePeriodTypeId = (int)timePeriodTypeId, - WorkedDate = item.WorkedDate + WorkedDate = DateUtils.AsUTC(item.WorkedDate) }; _context.HetTimeRecords.Add(time); @@ -548,7 +571,8 @@ public virtual ActionResult RentalAgreementsIdTimeRecordsBulkPos } // retrieve updated time records to return to ui - return new ObjectResult(new HetsResponse(_rentalAgreementRepo.GetTimeRecords(id, districtId))); + return new ObjectResult( + new HetsResponse(_rentalAgreementRepo.GetTimeRecords(id, districtId))); } #endregion @@ -1077,10 +1101,14 @@ public virtual ActionResult DeleteBlankRentalAgreementPost([ [HttpPost] [Route("updateCloneBlankAgreement/{id}")] [RequiresPermission(HetPermission.Login, HetPermission.WriteAccess)] - public virtual ActionResult CloneBlankRentalAgreementPost([FromRoute] int id, [FromBody] RentalAgreementDto agreement) + public virtual ActionResult CloneBlankRentalAgreementPost( + [FromRoute] int id, + [FromBody] RentalAgreementDto agreement) { // check the ids - if (id != agreement.RentalAgreementId) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (id != agreement.RentalAgreementId) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // get current users district int? districtId = UserAccountHelper.GetUsersDistrictId(_context); @@ -1088,12 +1116,16 @@ public virtual ActionResult CloneBlankRentalAgreementPost([F HetDistrict district = _context.HetDistricts.AsNoTracking() .FirstOrDefault(x => x.DistrictId.Equals(districtId)); - if (district == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (district == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // validate agreement id bool exists = _context.HetRentalAgreements.Any(a => a.RentalAgreementId == id); - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // add overtime rates List overtime = _context.HetProvincialRateTypes.AsNoTracking() @@ -1107,7 +1139,7 @@ public virtual ActionResult CloneBlankRentalAgreementPost([F .First(a => a.RentalAgreementId == id); // create new blank agreement as a duplicate - HetRentalAgreement newAgreement = new HetRentalAgreement + HetRentalAgreement newAgreement = new() { Number = RentalAgreementHelper.GetRentalAgreementNumber(district, _context), DistrictId = districtId, @@ -1118,13 +1150,17 @@ public virtual ActionResult CloneBlankRentalAgreementPost([F RateComment = oldAgreement.RateComment?.Trim(), EquipmentRate = oldAgreement.EquipmentRate, Note = oldAgreement.Note?.Trim(), - DatedOn = oldAgreement.DatedOn, AgreementCity = oldAgreement.AgreementCity }; + if (oldAgreement.DatedOn is DateTime datedOnUtc) + { + newAgreement.DatedOn = DateUtils.AsUTC(datedOnUtc); + } + foreach (HetRentalAgreementCondition condition in oldAgreement.HetRentalAgreementConditions) { - HetRentalAgreementCondition newCondition = new HetRentalAgreementCondition + HetRentalAgreementCondition newCondition = new() { RentalAgreementId = id, Comment = condition.Comment, @@ -1138,7 +1174,7 @@ public virtual ActionResult CloneBlankRentalAgreementPost([F { foreach (HetRentalAgreementRate rate in oldAgreement.HetRentalAgreementRates) { - HetRentalAgreementRate newRate = new HetRentalAgreementRate + HetRentalAgreementRate newRate = new() { RentalAgreementId = id, Comment = rate.Comment, @@ -1222,7 +1258,9 @@ where overtimeRate.Overtime ?? false [HttpGet] [RequiresPermission(HetPermission.Login)] [Route("latest/{projectId}/{equipmentId}")] - public virtual ActionResult GetLatestRentalAgreement([FromRoute] int projectId, [FromRoute] int equipmentId) + public virtual ActionResult GetLatestRentalAgreement( + [FromRoute] int projectId, + [FromRoute] int equipmentId) { // find the latest rental agreement HetRentalAgreement agreement = _context.HetRentalAgreements.AsNoTracking() @@ -1231,7 +1269,9 @@ public virtual ActionResult GetLatestRentalAgreement([FromRo x.ProjectId == projectId); // if nothing exists - return an error message - if (agreement == null) return new NotFoundObjectResult(new HetsResponse("HETS-35", ErrorViewModel.GetDescription("HETS-35", _configuration))); + if (agreement == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-35", ErrorViewModel.GetDescription("HETS-35", _configuration))); // get user's district int? districtId = UserAccountHelper.GetUsersDistrictId(_context); @@ -1241,14 +1281,19 @@ public virtual ActionResult GetLatestRentalAgreement([FromRo .First(x => x.DistrictId == districtId); int? fiscalYearStart = status.CurrentFiscalYear; - if (fiscalYearStart == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (fiscalYearStart == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); - DateTime fiscalStart = new DateTime((int)fiscalYearStart, 4, 1); + DateTime fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime((int)fiscalYearStart, 4, 1, 0, 0, 0, DateTimeKind.Unspecified)); // validate that agreement is in the current fiscal year - DateTime agreementDate = agreement.DatedOn ?? agreement.DbCreateTimestamp; + DateTime agreementDate = DateUtils.AsUTC(agreement.DatedOn ?? agreement.DbCreateTimestamp); - if (agreementDate < fiscalStart) return new NotFoundObjectResult(new HetsResponse("HETS-36", ErrorViewModel.GetDescription("HETS-36", _configuration))); + if (agreementDate < fiscalStart) + return new NotFoundObjectResult( + new HetsResponse("HETS-36", ErrorViewModel.GetDescription("HETS-36", _configuration))); // return to the client return new ObjectResult(new HetsResponse(_mapper.Map(agreement))); @@ -1302,9 +1347,13 @@ public virtual ActionResult> RentalAgreementsGe [HttpGet] [Route("aitReport")] [RequiresPermission(HetPermission.Login)] - public virtual ActionResult> AitReportGet([FromQuery] string projects, - [FromQuery] string districtEquipmentTypes, [FromQuery] string equipment, [FromQuery] string rentalAgreementNumber, - [FromQuery] DateTime? startDate, [FromQuery] DateTime? endDate) + public virtual ActionResult> AitReportGet( + [FromQuery] string projects, + [FromQuery] string districtEquipmentTypes, + [FromQuery] string equipment, + [FromQuery] string rentalAgreementNumber, + [FromQuery] DateTime? startDate, + [FromQuery] DateTime? endDate) { int?[] projectArray = ArrayHelper.ParseIntArray(projects); int?[] districtEquipmentTypeArray = ArrayHelper.ParseIntArray(districtEquipmentTypes); @@ -1326,7 +1375,8 @@ public virtual ActionResult> AitReportGet([FromQuery] s if (!string.IsNullOrWhiteSpace(rentalAgreementNumber)) { - agreements = agreements.Where(x => x.Number.ToUpper().Contains(rentalAgreementNumber.Trim().ToUpper())); + agreements = agreements.Where(x => + x.Number.ToUpper().Contains(rentalAgreementNumber.Trim().ToUpper())); } if (projectArray != null && projectArray.Length > 0) @@ -1336,7 +1386,8 @@ public virtual ActionResult> AitReportGet([FromQuery] s if (districtEquipmentTypeArray != null && districtEquipmentTypeArray.Length > 0) { - agreements = agreements.Where(x => districtEquipmentTypeArray.Contains(x.Equipment.DistrictEquipmentTypeId)); + agreements = agreements.Where(x => + districtEquipmentTypeArray.Contains(x.Equipment.DistrictEquipmentTypeId)); } if (equipmentArray != null && equipmentArray.Length > 0) @@ -1344,14 +1395,16 @@ public virtual ActionResult> AitReportGet([FromQuery] s agreements = agreements.Where(x => equipmentArray.Contains(x.EquipmentId)); } - if (startDate != null) + if (startDate is DateTime startDt) { - agreements = agreements.Where(x => x.DatedOn >= startDate); + DateTime startDtUtc = DateUtils.AsUTC(startDt); + agreements = agreements.Where(x => x.DatedOn >= startDtUtc); } - if (endDate != null) + if (endDate is DateTime endDt) { - agreements = agreements.Where(x => x.DatedOn <= endDate); + DateTime endDtUtc = DateUtils.AsUTC(endDt); + agreements = agreements.Where(x => x.DatedOn <= endDtUtc); } var result = agreements diff --git a/Server/HetsApi/Controllers/RentalRequestController.cs b/Server/HetsApi/Controllers/RentalRequestController.cs index 3a79621ba..3af54e1d7 100644 --- a/Server/HetsApi/Controllers/RentalRequestController.cs +++ b/Server/HetsApi/Controllers/RentalRequestController.cs @@ -16,6 +16,7 @@ using HetsData.Dtos; using HetsReport; using HetsCommon; +using DocumentFormat.OpenXml.Office2016.Excel; namespace HetsApi.Controllers { @@ -96,18 +97,23 @@ public virtual ActionResult> NoProjectsGet() [HttpPut] [Route("{id}")] [RequiresPermission(HetPermission.Login, HetPermission.WriteAccess)] - public virtual ActionResult RentalRequestsIdPut([FromRoute]int id, [FromBody]RentalRequestDto item) + public virtual ActionResult RentalRequestsIdPut( + [FromRoute]int id, + [FromBody]RentalRequestDto item) { if (item == null || id != item.RentalRequestId) { // not found - return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); } bool exists = _context.HetRentalRequests.Any(a => a.RentalRequestId == id); // not found - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // get record HetRentalRequest rentalRequest = _context.HetRentalRequests @@ -143,40 +149,48 @@ public virtual ActionResult RentalRequestsIdPut([FromRoute]int hiredCount > item.EquipmentCount) { //"HETS-07": "Rental Request count cannot be less than equipment already hired" - return new BadRequestObjectResult(new HetsResponse("HETS-07", ErrorViewModel.GetDescription("HETS-07", _configuration))); + return new BadRequestObjectResult( + new HetsResponse("HETS-07", ErrorViewModel.GetDescription("HETS-07", _configuration))); } // if the number of hired records is now "over the count" - then close if (hiredCount >= item.EquipmentCount) { int? statusIdComplete = StatusHelper.GetStatusId(HetRentalRequest.StatusComplete, "rentalRequestStatus", _context); - if (statusIdComplete == null) return new BadRequestObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusIdComplete == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); item.RentalRequestStatusTypeId = (int)statusIdComplete; item.Status = "Complete"; } int? statusId = StatusHelper.GetStatusId(item.Status, "rentalRequestStatus", _context); - if (statusId == null) return new BadRequestObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusId == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // update rental request rentalRequest.ConcurrencyControlNumber = item.ConcurrencyControlNumber; rentalRequest.RentalRequestStatusTypeId = (int)statusId; rentalRequest.EquipmentCount = item.EquipmentCount; - rentalRequest.ExpectedEndDate = item.ExpectedEndDate; - rentalRequest.ExpectedStartDate = item.ExpectedStartDate; + if (item.ExpectedEndDate is DateTime expectedEndDateUtc) + { + rentalRequest.ExpectedEndDate = DateUtils.AsUTC(expectedEndDateUtc); + } + if (item.ExpectedStartDate is DateTime expectedStartDateUtc) + { + rentalRequest.ExpectedStartDate = DateUtils.AsUTC(expectedStartDateUtc); + } rentalRequest.ExpectedHours = item.ExpectedHours; // do we have any attachments (only a single string is ever stored) if (item.RentalRequestAttachments != null && item.RentalRequestAttachments.Count > 0) { - if (rentalRequest.HetRentalRequestAttachments == null) - { - rentalRequest.HetRentalRequestAttachments = new List(); - } + rentalRequest.HetRentalRequestAttachments ??= new List(); - HetRentalRequestAttachment attachment = new HetRentalRequestAttachment + HetRentalRequestAttachment attachment = new() { Attachment = item.RentalRequestAttachments[0].Attachment }; @@ -225,7 +239,9 @@ public virtual ActionResult RentalRequestsViewOnlyPost([FromBo private ActionResult CreateRentalRequest(RentalRequestDto item, bool noProject = false) { // not found - if (item == null) return new BadRequestObjectResult(new HetsResponse("HETS-04", ErrorViewModel.GetDescription("HETS-04", _configuration))); + if (item == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-04", ErrorViewModel.GetDescription("HETS-04", _configuration))); // check if we have an existing rental request for the same // local area and equipment type - if so - throw an error @@ -235,12 +251,14 @@ private ActionResult CreateRentalRequest(RentalRequestDto item // // Note: leaving the "New" code in place in case this changes in the future int? statusIdInProgress = StatusHelper.GetStatusId(HetRentalRequest.StatusInProgress, "rentalRequestStatus", _context); - if (statusIdInProgress == null) return new NotFoundObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusIdInProgress == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); List requests = _context.HetRentalRequests - .Where(x => x.DistrictEquipmentTypeId == item.DistrictEquipmentType.DistrictEquipmentTypeId && - x.LocalAreaId == item.LocalArea.LocalAreaId && - x.RentalRequestStatusTypeId == statusIdInProgress) + .Where(x => x.DistrictEquipmentTypeId == item.DistrictEquipmentType.DistrictEquipmentTypeId + && x.LocalAreaId == item.LocalArea.LocalAreaId + && x.RentalRequestStatusTypeId == statusIdInProgress) .ToList(); // in Progress Rental Request already exists @@ -270,17 +288,25 @@ private ActionResult CreateRentalRequest(RentalRequestDto item } // create new rental request - HetRentalRequest rentalRequest = new HetRentalRequest + HetRentalRequest rentalRequest = new() { LocalAreaId = item.LocalArea.LocalAreaId, DistrictEquipmentTypeId = item.DistrictEquipmentType.DistrictEquipmentTypeId, RentalRequestStatusTypeId = (int)statusIdInProgress, EquipmentCount = item.EquipmentCount, - ExpectedEndDate = item.ExpectedEndDate, - ExpectedStartDate = item.ExpectedStartDate, ExpectedHours = item.ExpectedHours }; + if (item.ExpectedEndDate is DateTime expectedEndDateUtc) + { + rentalRequest.ExpectedEndDate = DateUtils.AsUTC(expectedEndDateUtc); + } + + if (item.ExpectedStartDate is DateTime expectedStartDateUtc) + { + rentalRequest.ExpectedStartDate = DateUtils.AsUTC(expectedStartDateUtc); + } + // is this a "project-less" request? - can't be hired from if (!noProject) { @@ -319,7 +345,7 @@ private ActionResult CreateRentalRequest(RentalRequestDto item if (item.RentalRequestAttachments != null && item.RentalRequestAttachments.Count > 0) { - HetRentalRequestAttachment attachment = new HetRentalRequestAttachment + HetRentalRequestAttachment attachment = new() { Attachment = item.RentalRequestAttachments.ElementAt(0).Attachment }; @@ -465,7 +491,12 @@ public virtual ActionResult RentalRequestsIdCancelGet([FromRou /// Inspection end date [HttpGet] [Route("search")] - public virtual ActionResult> RentalRequestsSearchGet([FromQuery]string localAreas, [FromQuery]string project, [FromQuery]string status, [FromQuery]DateTime? startDate, [FromQuery]DateTime? endDate) + public virtual ActionResult> RentalRequestsSearchGet( + [FromQuery]string localAreas, + [FromQuery]string project, + [FromQuery]string status, + [FromQuery]DateTime? startDate, + [FromQuery]DateTime? endDate) { int?[] localAreasArray = ArrayHelper.ParseIntArray(localAreas); @@ -492,14 +523,16 @@ public virtual ActionResult> RentalRequestsSearchGet([Fr data = data.Where(x => x.Project.Name.ToLower().Contains(project.ToLower())); } - if (startDate != null) + if (startDate is DateTime startDt) { - data = data.Where(x => x.ExpectedStartDate >= startDate); + DateTime startDtUtc = DateUtils.AsUTC(startDt); + data = data.Where(x => x.ExpectedStartDate >= startDtUtc); } - if (endDate != null) + if (endDate is DateTime endDt) { - data = data.Where(x => x.ExpectedStartDate <= endDate); + DateTime endDtUtc = DateUtils.AsUTC(endDt); + data = data.Where(x => x.ExpectedStartDate <= endDtUtc); } if (status != null) @@ -513,7 +546,7 @@ public virtual ActionResult> RentalRequestsSearchGet([Fr } // convert Rental Request Model to the "RentalRequestLite" Model - List result = new List(); + List result = new(); foreach (HetRentalRequest item in data) { @@ -535,20 +568,24 @@ public virtual ActionResult> RentalRequestsSearchGet([Fr [HttpGet] [Route("{id}/rotationList")] [RequiresPermission(HetPermission.Login)] - public virtual ActionResult RentalRequestsIdRotationListIdGet([FromRoute]int id) + public virtual ActionResult RentalRequestsIdRotationListIdGet( + [FromRoute]int id) { bool exists = _context.HetRentalRequests.Any(a => a.RentalRequestId == id); // not found - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // get the scoring rules - SeniorityScoringRules scoringRules = new SeniorityScoringRules(_configuration, (errMessage, ex) => { + SeniorityScoringRules scoringRules = new(_configuration, (errMessage, ex) => { _logger.LogError(errMessage); _logger.LogError(ex.ToString()); }); - return new ObjectResult(new HetsResponse(_rentalRequestRepo.GetRecordWithRotationList(id, scoringRules))); + return new ObjectResult( + new HetsResponse(_rentalRequestRepo.GetRecordWithRotationList(id, scoringRules))); } /// @@ -560,26 +597,39 @@ public virtual ActionResult RentalRequestsIdRotationListIdGet( [HttpPut] [Route("{id}/rentalRequestRotationList")] [RequiresPermission(HetPermission.Login, HetPermission.WriteAccess)] - public virtual ActionResult RentalRequestIdRotationListIdPut([FromRoute]int id, [FromBody]RentalRequestRotationListDto item) + public virtual ActionResult RentalRequestIdRotationListIdPut( + [FromRoute]int id, + [FromBody]RentalRequestRotationListDto item) { // not found - if (item == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (item == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); bool exists = _context.HetRentalRequests.Any(a => a.RentalRequestId == id); // not found - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + + int? statusId = StatusHelper.GetStatusId( + HetRentalRequest.StatusInProgress, "rentalRequestStatus", _context); - int? statusId = StatusHelper.GetStatusId(HetRentalRequest.StatusInProgress, "rentalRequestStatus", _context); - if (statusId == null) return new NotFoundObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusId == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // check if we have the rental request that is In Progress exists = _context.HetRentalRequests - .Any(a => a.RentalRequestId == id && - a.RentalRequestStatusTypeId == statusId); + .Any(a => + a.RentalRequestId == id + && a.RentalRequestStatusTypeId == statusId); // rental request must be "in progress" - if (!exists) return new BadRequestObjectResult(new HetsResponse("HETS-06", ErrorViewModel.GetDescription("HETS-06", _configuration))); + if (!exists) + return new BadRequestObjectResult( + new HetsResponse("HETS-06", ErrorViewModel.GetDescription("HETS-06", _configuration))); // get rental request record HetRentalRequest request = _context.HetRentalRequests @@ -595,7 +645,9 @@ public virtual ActionResult RentalRequestIdRotationListIdPut([ .FirstOrDefault(a => a.RentalRequestRotationListId == item.RentalRequestRotationListId); // not found - if (requestRotationList == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (requestRotationList == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // update rotation list record int tempEquipmentId = item.Equipment.EquipmentId; @@ -607,79 +659,89 @@ public virtual ActionResult RentalRequestIdRotationListIdPut([ requestRotationList.Note = item.Note; requestRotationList.OfferRefusalReason = item.OfferRefusalReason; requestRotationList.OfferResponse = item.OfferResponse; - requestRotationList.OfferResponseDatetime = item.OfferResponseDatetime; + requestRotationList.OfferResponseDatetime = + item.OfferResponseDatetime is DateTime offerResponseDt + ? DateUtils.AsUTC(offerResponseDt) : null; + requestRotationList.WasAsked = item.WasAsked; requestRotationList.OfferResponseNote = item.OfferResponseNote; + NotFoundObjectResult notFound = ModifyRentalAgreement(item, request, tempEquipmentId, requestRotationList); + if (notFound != null) return notFound; + + // can we "Complete" this rental request (if the Yes or Forced Hires = Request.EquipmentCount) + int equipmentRequestCount = request.EquipmentCount; + int countOfYeses = GetCountYeses(request); + + if (countOfYeses >= equipmentRequestCount) + { + int? statusIdComplete = StatusHelper.GetStatusId( + HetRentalRequest.StatusComplete, "rentalRequestStatus", _context); + + if (statusIdComplete == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + + request.RentalRequestStatusTypeId = (int)statusIdComplete; + request.Status = "Complete"; + request.FirstOnRotationList = null; + } + + RentalRequestHelper.UpdateRotationList(request); + + // save the changes + _context.SaveChanges(); + + // get the scoring rules + SeniorityScoringRules scoringRules = new(_configuration, (errMessage, ex) => { + _logger.LogError("{errMessage}", errMessage); + _logger.LogError("{exception}", ex); + }); + + return new ObjectResult( + new HetsResponse(_rentalRequestRepo.GetRecordWithRotationList(id, scoringRules))); + } + + private static bool ShouldModifyRentalAgreement(RentalRequestRotationListDto item) + { + return item.IsForceHire == true + || item.OfferResponse.Equals("Yes", StringComparison.InvariantCultureIgnoreCase); + } + + private NotFoundObjectResult ModifyRentalAgreement( + RentalRequestRotationListDto item, + HetRentalRequest request, + int tempEquipmentId, + HetRentalRequestRotationList requestRotationList) + { // do we need to create or modify a Rental Agreement? - if (item.IsForceHire == true || - item.OfferResponse.Equals("Yes", StringComparison.InvariantCultureIgnoreCase)) + if (ShouldModifyRentalAgreement(item)) { // get rental agreement record HetRentalAgreement rentalAgreement = _context.HetRentalAgreements .FirstOrDefault(a => a.RentalAgreementId == item.RentalAgreementId); // create rental agreement if it doesn't exist - if (rentalAgreement == null) - { - // generate the rental agreement number - string agreementNumber = RentalAgreementHelper.GetRentalAgreementNumber(item.Equipment?.LocalAreaId, _context); - - // get user info - agreement city - CurrentUserDto user = UserAccountHelper.GetUser(_context, _httpContext); - string agreementCity = user.AgreementCity; - - int? rateTypeId = StatusHelper.GetRatePeriodId(HetRatePeriodType.PeriodHourly, _context); - if (rateTypeId == null) return new NotFoundObjectResult(new HetsResponse("HETS-24", ErrorViewModel.GetDescription("HETS-24", _configuration))); - - rentalAgreement = new HetRentalAgreement - { - ProjectId = request.ProjectId, - DistrictId = request.Project.District.DistrictId, - EquipmentId = tempEquipmentId, - Number = agreementNumber, - RatePeriodTypeId = (int)rateTypeId, - AgreementCity = agreementCity - }; + (HetRentalAgreement agreement, NotFoundObjectResult notFound) = + CreateRentalAgreement(rentalAgreement, item, request, tempEquipmentId); - // add overtime rates - List overtime = _context.HetProvincialRateTypes.AsNoTracking() - .Where(x => x.Overtime) - .ToList(); + if (notFound != null) return notFound; + rentalAgreement = agreement; - // agreement overtime records (default overtime flag) - foreach (HetProvincialRateType rate in overtime) - { - // add the rate - HetRentalAgreementRate newAgreementRate = new HetRentalAgreementRate - { - Comment = rate.Description, - ComponentName = rate.RateType, - Overtime = true, - Active = rate.Active, - IsIncludedInTotal = rate.IsIncludedInTotal, - Rate = rate.Rate - }; - - if (rentalAgreement.HetRentalAgreementRates == null) - { - rentalAgreement.HetRentalAgreementRates = new List(); - } - - rentalAgreement.HetRentalAgreementRates.Add(newAgreementRate); - } - - _context.HetRentalAgreements.Add(rentalAgreement); - } + int? statusIdAgreement = StatusHelper.GetStatusId( + HetRentalAgreement.StatusActive, "rentalAgreementStatus", _context); - int? statusIdAgreement = StatusHelper.GetStatusId(HetRentalAgreement.StatusActive, "rentalAgreementStatus", _context); - if (statusIdAgreement == null) return new NotFoundObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); + if (statusIdAgreement == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); // update rental agreement rentalAgreement.RentalAgreementStatusTypeId = (int)statusIdAgreement; rentalAgreement.DatedOn = DateTime.UtcNow; rentalAgreement.EstimateHours = request.ExpectedHours; - rentalAgreement.EstimateStartWork = request.ExpectedStartDate; + if (request.ExpectedStartDate is DateTime expectedStartDateUtc) { + rentalAgreement.EstimateStartWork = DateUtils.AsUTC(expectedStartDateUtc); + } rentalAgreement.RentalRequestId = request.RentalRequestId; rentalAgreement.RentalRequestRotationListId = requestRotationList.RentalRequestRotationListId; @@ -692,46 +754,91 @@ public virtual ActionResult RentalRequestIdRotationListIdPut([ requestRotationList.RentalAgreement = rentalAgreement; } - // can we "Complete" this rental request (if the Yes or Forced Hires = Request.EquipmentCount) + return null; + } + + private (HetRentalAgreement agreement, NotFoundObjectResult notFound) CreateRentalAgreement( + HetRentalAgreement rentalAgreement, + RentalRequestRotationListDto item, + HetRentalRequest request, + int tempEquipmentId) + { + // create rental agreement if it doesn't exist + if (rentalAgreement == null) + { + // generate the rental agreement number + string agreementNumber = RentalAgreementHelper.GetRentalAgreementNumber( + item.Equipment?.LocalAreaId, _context); + + // get user info - agreement city + CurrentUserDto user = UserAccountHelper.GetUser(_context, _httpContext); + string agreementCity = user.AgreementCity; + + int? rateTypeId = StatusHelper.GetRatePeriodId(HetRatePeriodType.PeriodHourly, _context); + if (rateTypeId == null) + return ( + rentalAgreement, + new NotFoundObjectResult( + new HetsResponse("HETS-24", ErrorViewModel.GetDescription("HETS-24", _configuration)))); + + rentalAgreement = new HetRentalAgreement + { + ProjectId = request.ProjectId, + DistrictId = request.Project.District.DistrictId, + EquipmentId = tempEquipmentId, + Number = agreementNumber, + RatePeriodTypeId = (int)rateTypeId, + AgreementCity = agreementCity + }; + + // add overtime rates + List overtime = _context.HetProvincialRateTypes.AsNoTracking() + .Where(x => x.Overtime) + .ToList(); + + // agreement overtime records (default overtime flag) + foreach (HetProvincialRateType rate in overtime) + { + // add the rate + HetRentalAgreementRate newAgreementRate = new() + { + Comment = rate.Description, + ComponentName = rate.RateType, + Overtime = true, + Active = rate.Active, + IsIncludedInTotal = rate.IsIncludedInTotal, + Rate = rate.Rate + }; + + rentalAgreement.HetRentalAgreementRates ??= new List(); + rentalAgreement.HetRentalAgreementRates.Add(newAgreementRate); + } + + _context.HetRentalAgreements.Add(rentalAgreement); + } + + return (rentalAgreement, null); + } + + private static int GetCountYeses(HetRentalRequest request) + { int countOfYeses = 0; - int equipmentRequestCount = request.EquipmentCount; foreach (HetRentalRequestRotationList rotationList in request.HetRentalRequestRotationLists) { if (rotationList.OfferResponse != null && rotationList.OfferResponse.Equals("Yes", StringComparison.InvariantCultureIgnoreCase)) { - countOfYeses = countOfYeses + 1; + countOfYeses++; } else if (rotationList.IsForceHire != null && rotationList.IsForceHire == true) { - countOfYeses = countOfYeses + 1; + countOfYeses++; } } - if (countOfYeses >= equipmentRequestCount) - { - int? statusIdComplete = StatusHelper.GetStatusId(HetRentalRequest.StatusComplete, "rentalRequestStatus", _context); - if (statusIdComplete == null) return new NotFoundObjectResult(new HetsResponse("HETS-23", ErrorViewModel.GetDescription("HETS-23", _configuration))); - - request.RentalRequestStatusTypeId = (int)statusIdComplete; - request.Status = "Complete"; - request.FirstOnRotationList = null; - } - - RentalRequestHelper.UpdateRotationList(request); - - // save the changes - _context.SaveChanges(); - - // get the scoring rules - SeniorityScoringRules scoringRules = new SeniorityScoringRules(_configuration, (errMessage, ex) => { - _logger.LogError(errMessage); - _logger.LogError(ex.ToString()); - }); - - return new ObjectResult(new HetsResponse(_rentalRequestRepo.GetRecordWithRotationList(id, scoringRules))); + return countOfYeses; } #endregion @@ -746,33 +853,37 @@ public virtual ActionResult RentalRequestIdRotationListIdPut([ [HttpGet] [Route("{id}/attachments")] [RequiresPermission(HetPermission.Login)] - public virtual ActionResult> RentalRequestsIdAttachmentsGet([FromRoute]int id) + public virtual ActionResult> RentalRequestsIdAttachmentsGet( + [FromRoute]int id) { bool exists = _context.HetRentalRequests.Any(a => a.RentalRequestId == id); // not found - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); HetRentalRequest equipment = _context.HetRentalRequests.AsNoTracking() .Include(x => x.HetDigitalFiles) .First(a => a.RentalRequestId == id); // extract the attachments and update properties for UI - List attachments = new List(); + List attachments = new(); foreach (HetDigitalFile attachment in equipment.HetDigitalFiles) { if (attachment != null) { attachment.FileSize = attachment.FileContents.Length; - attachment.LastUpdateTimestamp = attachment.AppLastUpdateTimestamp; + attachment.LastUpdateTimestamp = DateUtils.AsUTC(attachment.AppLastUpdateTimestamp); attachment.LastUpdateUserid = attachment.AppLastUpdateUserid; attachment.UserName = UserHelper.GetUserName(attachment.LastUpdateUserid, _context); attachments.Add(attachment); } } - return new ObjectResult(new HetsResponse(_mapper.Map>(attachments))); + return new ObjectResult( + new HetsResponse(_mapper.Map>(attachments))); } #endregion @@ -789,14 +900,20 @@ public virtual ActionResult> RentalRequestsIdAttachmentsGet [HttpGet] [Route("{id}/history")] [RequiresPermission(HetPermission.Login)] - public virtual ActionResult> RentalRequestsIdHistoryGet([FromRoute]int id, [FromQuery]int? offset, [FromQuery]int? limit) + public virtual ActionResult> RentalRequestsIdHistoryGet( + [FromRoute]int id, + [FromQuery]int? offset, + [FromQuery]int? limit) { bool exists = _context.HetRentalRequests.Any(a => a.RentalRequestId == id); // not found - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); - return new ObjectResult(new HetsResponse(RentalRequestHelper.GetHistoryRecords(id, offset, limit, _context))); + return new ObjectResult( + new HetsResponse(RentalRequestHelper.GetHistoryRecords(id, offset, limit, _context))); } /// @@ -808,13 +925,15 @@ public virtual ActionResult> RentalRequestsIdHistoryGet([FromRoute [HttpPost] [Route("{id}/history")] [RequiresPermission(HetPermission.Login, HetPermission.WriteAccess)] - public virtual ActionResult> RentalRequestsIdHistoryPost([FromRoute]int id, [FromBody]History item) + public virtual ActionResult> RentalRequestsIdHistoryPost( + [FromRoute]int id, + [FromBody]History item) { bool exists = _context.HetRentalRequests.Any(a => a.RentalRequestId == id); if (exists) { - HetHistory history = new HetHistory + HetHistory history = new() { HistoryId = 0, HistoryText = item.HistoryText, @@ -826,7 +945,9 @@ public virtual ActionResult> RentalRequestsIdHistoryPost([FromRout _context.SaveChanges(); } - return new ObjectResult(new HetsResponse(RentalRequestHelper.GetHistoryRecords(id, null, null, _context))); + return new ObjectResult( + new HetsResponse( + RentalRequestHelper.GetHistoryRecords(id, null, null, _context))); } #endregion @@ -940,8 +1061,11 @@ public virtual ActionResult> RentalRequestsIdNotePost([FromRoute]i [HttpGet] [Route("hireReport")] [RequiresPermission(HetPermission.Login)] - public virtual ActionResult> RentalRequestsHiresGet([FromQuery]string localAreas, [FromQuery]string projects, - [FromQuery]string owners, [FromQuery]string equipment) + public virtual ActionResult> RentalRequestsHiresGet( + [FromQuery]string localAreas, + [FromQuery]string projects, + [FromQuery]string owners, + [FromQuery]string equipment) { int?[] localAreasArray = ArrayHelper.ParseIntArray(localAreas); int?[] projectArray = ArrayHelper.ParseIntArray(projects); @@ -955,10 +1079,13 @@ public virtual ActionResult> RentalRequestsHiresGet([Fr HetDistrictStatus district = _context.HetDistrictStatuses.AsNoTracking() .FirstOrDefault(x => x.DistrictId == districtId); - if (district?.CurrentFiscalYear == null) return new BadRequestObjectResult(new HetsResponse("HETS-30", ErrorViewModel.GetDescription("HETS-30", _configuration))); + if (district?.CurrentFiscalYear == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-30", ErrorViewModel.GetDescription("HETS-30", _configuration))); int fiscalYear = (int)district.CurrentFiscalYear; // status table uses the start of the year - DateTime fiscalStart = new DateTime(fiscalYear, 3, 31); // look for all records AFTER the 31st + DateTime fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(fiscalYear, 3, 31, 0, 0, 0, DateTimeKind.Unspecified)); // look for all records AFTER the 31st IQueryable data = _context.HetRentalRequestRotationLists.AsNoTracking() .Include(x => x.RentalRequest) @@ -968,9 +1095,10 @@ public virtual ActionResult> RentalRequestsHiresGet([Fr .ThenInclude(y => y.Project) .Include(x => x.Equipment) .ThenInclude(y => y.Owner) - .Where(x => x.RentalRequest.LocalArea.ServiceArea.DistrictId.Equals(districtId) && - x.AskedDateTime > fiscalStart && - (x.IsForceHire == true || x.OfferResponse.ToLower() == "no")); + .Where(x => + x.RentalRequest.LocalArea.ServiceArea.DistrictId.Equals(districtId) + && x.AskedDateTime > fiscalStart + && (x.IsForceHire == true || x.OfferResponse.ToLower() == "no")); if (localAreasArray != null && localAreasArray.Length > 0) { @@ -993,7 +1121,7 @@ public virtual ActionResult> RentalRequestsHiresGet([Fr } // convert Rental Request Model to the "RentalRequestHires" Model - List result = new List(); + List result = new(); var items = data.ToList(); foreach (HetRentalRequestRotationList item in items) @@ -1023,18 +1151,20 @@ public virtual IActionResult GetSeniorityList(int id, bool counterCopy = false) .FirstOrDefault(a => a.RentalRequestId == id); if (request == null) - return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); var fiscalYear = request.FiscalYear; - var fiscalStart = new DateTime(fiscalYear - 1, 4, 1); var yearMinus1 = $"{fiscalYear - 2}/{fiscalYear - 1}"; var yearMinus2 = $"{fiscalYear - 3}/{fiscalYear - 2}"; var yearMinus3 = $"{fiscalYear - 4}/{fiscalYear - 3}"; - var seniorityList = new SeniorityListReportViewModel(); - seniorityList.Classification = $"23010-22/{(fiscalYear - 1).ToString().Substring(2, 2)}-{fiscalYear.ToString().Substring(2, 2)}"; - seniorityList.GeneratedOn = $"{DateUtils.ConvertUtcToPacificTime(request.AppCreateTimestamp):dd-MM-yyyy H:mm:ss}"; + var seniorityList = new SeniorityListReportViewModel + { + Classification = $"23010-22/{(fiscalYear - 1).ToString().Substring(2, 2)}-{fiscalYear.ToString().Substring(2, 2)}", + GeneratedOn = $"{DateUtils.ConvertUtcToPacificTime(request.AppCreateTimestamp):dd-MM-yyyy H:mm:ss}" + }; var scoringRules = new SeniorityScoringRules(_configuration, (errMessage, ex) => { _logger.LogError(errMessage); @@ -1067,7 +1197,10 @@ public virtual IActionResult GetSeniorityList(int id, bool counterCopy = false) { listRecord.SeniorityList.Add(SeniorityListHelper.ToSeniorityViewModel(equipment, numberOfBlocks)); } - + // TH-112626 + listRecord.SeniorityList = listRecord.SeniorityList + .OrderByDescending(x => Convert.ToDecimal(x.Seniority)) + .ToList(); string documentName = $"SeniorityList-{DateTime.Now:yyyy-MM-dd}{(counterCopy ? "-(CounterCopy)" : "")}.docx"; byte[] document = SeniorityList.GetSeniorityList(seniorityList, documentName, counterCopy, (errMessage, ex) => { _logger.LogError(errMessage); @@ -1075,7 +1208,7 @@ public virtual IActionResult GetSeniorityList(int id, bool counterCopy = false) }); // return document - FileContentResult result = new FileContentResult(document, "application/vnd.openxmlformats-officedocument.wordprocessingml.document") + FileContentResult result = new(document, "application/vnd.openxmlformats-officedocument.wordprocessingml.document") { FileDownloadName = documentName }; diff --git a/Server/HetsApi/Controllers/ReportController.cs b/Server/HetsApi/Controllers/ReportController.cs index 77dd95c1e..d2f3f1a7c 100644 --- a/Server/HetsApi/Controllers/ReportController.cs +++ b/Server/HetsApi/Controllers/ReportController.cs @@ -11,6 +11,8 @@ using HetsData.Dtos; using AutoMapper; using Microsoft.Extensions.Logging; +using System; +using HetsCommon; namespace HetsApi.Controllers { @@ -53,8 +55,8 @@ public virtual ActionResult> BatchReportGet() { ReportId = x.ReportId, DistrictId = x.DistrictId, - StartDate = x.StartDate, - EndDate = x.EndDate, + StartDate = x.StartDate is DateTime startDateUtc ? DateUtils.AsUTC(startDateUtc) : null, + EndDate = x.EndDate is DateTime endDateUtc ? DateUtils.AsUTC(endDateUtc) : null, Complete = x.Complete ?? false }).ToList(); diff --git a/Server/HetsApi/Controllers/TimeRecordController.cs b/Server/HetsApi/Controllers/TimeRecordController.cs index c6b74d07e..d77b0749c 100644 --- a/Server/HetsApi/Controllers/TimeRecordController.cs +++ b/Server/HetsApi/Controllers/TimeRecordController.cs @@ -11,6 +11,7 @@ using Microsoft.EntityFrameworkCore; using AutoMapper; using HetsData.Dtos; +using HetsCommon; namespace HetsApi.Controllers { @@ -71,8 +72,11 @@ public virtual ActionResult TimeRecordsIdDeletePost([FromRoute]in [HttpGet] [Route("search")] [RequiresPermission(HetPermission.Login)] - public virtual ActionResult> TimeRecordSearchGet([FromQuery]string localAreas, - [FromQuery]string projects, [FromQuery]string owners, [FromQuery]string equipment) + public virtual ActionResult> TimeRecordSearchGet( + [FromQuery]string localAreas, + [FromQuery]string projects, + [FromQuery]string owners, + [FromQuery]string equipment) { int?[] localAreasArray = ArrayHelper.ParseIntArray(localAreas); int?[] projectArray = ArrayHelper.ParseIntArray(projects); @@ -86,10 +90,13 @@ public virtual ActionResult> TimeRecordSearchGet([Fro HetDistrictStatus district = _context.HetDistrictStatuses.AsNoTracking() .FirstOrDefault(x => x.DistrictId == districtId); - if (district?.CurrentFiscalYear == null) return new BadRequestObjectResult(new HetsResponse("HETS-30", ErrorViewModel.GetDescription("HETS-30", _configuration))); + if (district?.CurrentFiscalYear == null) + return new BadRequestObjectResult( + new HetsResponse("HETS-30", ErrorViewModel.GetDescription("HETS-30", _configuration))); int fiscalYear = (int)district.CurrentFiscalYear; // status table uses the start of the year - DateTime fiscalStart = new DateTime(fiscalYear, 3, 31); // look for all records AFTER the 31st + DateTime fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(fiscalYear, 3, 31, 0, 0, 0, DateTimeKind.Unspecified)); // look for all records AFTER the 31st // only return active equipment / projects and agreements IQueryable data = _context.HetTimeRecords.AsNoTracking() @@ -105,8 +112,9 @@ public virtual ActionResult> TimeRecordSearchGet([Fro .Include(x => x.RentalAgreement) .ThenInclude(x => x.Equipment) .ThenInclude(z => z.Owner) - .Where(x => x.RentalAgreement.Equipment.LocalArea.ServiceArea.DistrictId.Equals(districtId) && - x.WorkedDate > fiscalStart); + .Where(x => + x.RentalAgreement.Equipment.LocalArea.ServiceArea.DistrictId.Equals(districtId) + && x.WorkedDate > fiscalStart); if (localAreasArray != null && localAreasArray.Length > 0) { @@ -129,7 +137,7 @@ public virtual ActionResult> TimeRecordSearchGet([Fro } // convert Time Model to the "TimeLite" Model - List result = new List(); + List result = new(); foreach (HetTimeRecord item in data) { diff --git a/Server/HetsApi/Controllers/UserController.cs b/Server/HetsApi/Controllers/UserController.cs index 7e207a869..6b1e2bbea 100644 --- a/Server/HetsApi/Controllers/UserController.cs +++ b/Server/HetsApi/Controllers/UserController.cs @@ -10,6 +10,8 @@ using AutoMapper; using HetsData.Dtos; using HetsData.Repositories; +using HetsCommon; +using System; namespace HetsApi.Controllers { @@ -374,7 +376,9 @@ public virtual ActionResult> UsersIdRolesGet([FromRoute] int i bool exists = _context.HetUsers.Any(x => x.UserId == id); // not found - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // get record var user = _userRepo.GetRecord(id); @@ -392,32 +396,42 @@ public virtual ActionResult> UsersIdRolesGet([FromRoute] int i [HttpPost] [Route("{id}/roles")] [RequiresPermission(HetPermission.UserManagement, HetPermission.WriteAccess)] - public virtual ActionResult> UsersIdRolesPost([FromRoute] int id, [FromBody] UserRoleDto item) + public virtual ActionResult> UsersIdRolesPost( + [FromRoute] int id, + [FromBody] UserRoleDto item) { //check for user bool exists = _context.HetUsers.Any(x => x.UserId == id); - if (!exists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!exists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // check the role id bool roleExists = _context.HetRoles.Any(x => x.RoleId == item.RoleId); - if (!roleExists) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!roleExists) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // check the user exists and return only active roles var user = _userRepo.GetRecord(id, excludeInactiveRoles: true); - if (user == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (user == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); //check if user already has the same role active bool activeRoleExists = user.UserRoles.Any(x => x.RoleId == item.RoleId); - if (activeRoleExists) return new NotFoundObjectResult(new HetsResponse("HETS-45", ErrorViewModel.GetDescription("HETS-45", _configuration))); + if (activeRoleExists) + return new NotFoundObjectResult( + new HetsResponse("HETS-45", ErrorViewModel.GetDescription("HETS-45", _configuration))); // create a new UserRole record - HetUserRole userRole = new HetUserRole + HetUserRole userRole = new() { RoleId = item.RoleId, UserId = id, - EffectiveDate = item.EffectiveDate, - ExpiryDate = item.ExpiryDate + EffectiveDate = DateUtils.AsUTC(item.EffectiveDate), + ExpiryDate = item.ExpiryDate is DateTime expiryDateUtc ? DateUtils.AsUTC(expiryDateUtc) : null, }; _context.HetUserRoles.Add(userRole); @@ -440,24 +454,32 @@ public virtual ActionResult> UsersIdRolesPost([FromRoute] int [HttpPut] [Route("{id}/roles")] [RequiresPermission(HetPermission.UserManagement, HetPermission.WriteAccess)] - public virtual ActionResult> UsersIdRolesPut([FromRoute] int id, [FromBody] UserRoleDto[] items) + public virtual ActionResult> UsersIdRolesPut( + [FromRoute] int id, + [FromBody] UserRoleDto[] items) { //confirm user exists bool userExists = _context.HetUsers.Any(x => x.UserId == id); - if (!userExists || items == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (!userExists || items == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); //confirm all items belong to the user, using UserRoleId //confirm all items exist in database foreach (var item in items) { var result = _context.HetUserRoles.FirstOrDefault(x => x.UserRoleId == item.UserRoleId && x.UserId == id); - if (result == null) return new NotFoundObjectResult(new HetsResponse("HETS-44", ErrorViewModel.GetDescription("HETS-44", _configuration))); + if (result == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-44", ErrorViewModel.GetDescription("HETS-44", _configuration))); } // get record var user = _userRepo.GetRecord(id); - if (user.UserRoles == null) return new NotFoundObjectResult(new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); + if (user.UserRoles == null) + return new NotFoundObjectResult( + new HetsResponse("HETS-01", ErrorViewModel.GetDescription("HETS-01", _configuration))); // iterate the roles and update effective date foreach (var item in items) @@ -466,7 +488,9 @@ public virtual ActionResult> UsersIdRolesPut([FromRoute] int i if (role.ExpiryDate != item.ExpiryDate) { - role.ExpiryDate = item.ExpiryDate; + role.ExpiryDate = + item.ExpiryDate is DateTime expiryDateUtc ? + DateUtils.AsUTC(expiryDateUtc) : null; } } _context.SaveChanges(); diff --git a/Server/HetsApi/Helpers/UserAccountHelper.cs b/Server/HetsApi/Helpers/UserAccountHelper.cs index 9f825d9aa..d6e9bad2e 100644 --- a/Server/HetsApi/Helpers/UserAccountHelper.cs +++ b/Server/HetsApi/Helpers/UserAccountHelper.cs @@ -118,10 +118,7 @@ public static HetUser GetUser(DbAppContext context, string username, string guid user = GetUserByGuid(guid, context); } - if (user == null) - { - user = GetUserBySmUserId(username, context); - } + user ??= GetUserBySmUserId(username, context); if (user == null) { @@ -224,7 +221,8 @@ public static HetUser GetUserBySmUserId(string smUserId, DbAppContext context) /// /// /// - public static HetBusinessUser GetBusinessUser(DbAppContext context, string username, string bizGuid, string bizName, string email, string guid) + public static HetBusinessUser GetBusinessUser( + DbAppContext context, string username, string bizGuid, string bizName, string email, string guid) { // find the business HetBusiness business = context.HetBusinesses.AsNoTracking() @@ -309,7 +307,7 @@ public static HetBusinessUser GetBusinessUser(DbAppContext context, string usern } // add the "Business Logon" role - HetBusinessUserRole userRole = new HetBusinessUserRole + HetBusinessUserRole userRole = new() { RoleId = StatusHelper.GetRoleId("Business BCeID", context), EffectiveDate = DateTime.UtcNow.AddMinutes(-10), diff --git a/Server/HetsApi/HetsApi.csproj b/Server/HetsApi/HetsApi.csproj index e29a69e10..02d49c87e 100644 --- a/Server/HetsApi/HetsApi.csproj +++ b/Server/HetsApi/HetsApi.csproj @@ -1,7 +1,7 @@  - net5.0 + net7.0 The Api server for the Hired Equipment Tracking System Copyright© 2017, Province of British Columbia. Hets Api Server @@ -12,7 +12,7 @@ 1.0.0.0 sprint1 - 1.10.8.0 + 1.10.9.0 @@ -35,34 +35,34 @@ - - - - - - - - - - - + + + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + - - - + + + diff --git a/Server/HetsApi/Model/AitReport.cs b/Server/HetsApi/Model/AitReport.cs index 897684181..b7d3a86a0 100644 --- a/Server/HetsApi/Model/AitReport.cs +++ b/Server/HetsApi/Model/AitReport.cs @@ -1,9 +1,7 @@ -using HetsData.Entities; +using HetsCommon; +using HetsData.Entities; using Newtonsoft.Json; using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace HetsApi.Model { @@ -30,8 +28,21 @@ public class AitReport public string ProjectNumber { get; set; } public string ProjectName { get; set; } - public DateTime? DatedOn { get; set; } - public DateTime? StartDate { get; set; } + private DateTime? _datedOn; + public DateTime? DatedOn { + get => _datedOn is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _datedOn = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _startDate; + public DateTime? StartDate { + get => _startDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _startDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } public static AitReport MapFromHetRentalAgreement(HetRentalAgreement agreement) { @@ -50,8 +61,11 @@ public static AitReport MapFromHetRentalAgreement(HetRentalAgreement agreement) ProjectNumber = agreement.Project?.ProvincialProjectNumber, ProjectName = agreement.Project?.Name, - DatedOn = agreement.DatedOn, - StartDate = agreement.EstimateStartWork, + DatedOn = agreement.DatedOn is DateTime datedOnUtc ? + DateUtils.AsUTC(datedOnUtc) : null, + + StartDate = agreement.EstimateStartWork is DateTime estimateStartWorkUtc ? + DateUtils.AsUTC(estimateStartWorkUtc) : null, }; return report; diff --git a/Server/HetsApi/Program.cs b/Server/HetsApi/Program.cs index 420cdb864..ea8003a10 100644 --- a/Server/HetsApi/Program.cs +++ b/Server/HetsApi/Program.cs @@ -3,32 +3,237 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Serilog; +using System; +using AutoMapper; +using HetsApi.Authentication; +using HetsData.Entities; +using HetsData.Hangfire; +using HetsData.Repositories; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.IdentityModel.Logging; +using HetsApi.Middlewares; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Swashbuckle.AspNetCore.SwaggerUI; +using Microsoft.Extensions.DependencyInjection; +using HetsData.Mappings; +using Serilog.Ui.Web; +using Serilog.Ui.PostgreSqlProvider; +using Microsoft.EntityFrameworkCore.Diagnostics; +using HetsApi.Authorization; +using Hangfire; +using Hangfire.PostgreSql; +using Microsoft.OpenApi.Models; +using System.Net.Mime; +using System.Text.Json; +using System.Linq; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.Authorization; +using Newtonsoft.Json.Serialization; +using Microsoft.EntityFrameworkCore; -namespace HetsApi +try { - /// - /// The main Program for the application. - /// - public static class Program + var builder = WebApplication.CreateBuilder(args); + + // Register services here + builder.Host.UseSerilog(); + builder.Configuration.AddEnvironmentVariables(); + + Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(builder.Configuration) + .CreateLogger(); + + IdentityModelEventSource.ShowPII = true; + string connectionString = GetConnectionString(builder.Configuration); + + // add http context accessor + builder.Services.AddHttpContextAccessor(); + + // add auto mapper + var mappingConfig = new MapperConfiguration(cfg => + { + cfg.AddProfile(new EntityToDtoProfile()); + cfg.AddProfile(new DtoToEntityProfile()); + cfg.AddProfile(new EntityToEntityProfile()); + }); + + var mapper = mappingConfig.CreateMapper(); + builder.Services.AddSingleton(mapper); + builder.Services.AddSerilogUi(options => options.UseNpgSql(connectionString, "het_log")); + + // add database context + builder.Services.AddDbContext(options => + { + options.UseNpgsql(connectionString, o => o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)); + options.ConfigureWarnings(o => o.Ignore(CoreEventId.RowLimitingOperationWithoutOrderByWarning)); + }); + + builder.Services.AddDbContext(options => + { + options.UseNpgsql(connectionString, o => o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)); + options.ConfigureWarnings(o => o.Ignore(CoreEventId.RowLimitingOperationWithoutOrderByWarning)); + }); + + builder.Services.AddScoped(); + + builder.Services + .AddControllers(options => + { + var policy = new AuthorizationPolicyBuilder() + .RequireAuthenticatedUser() + .Build(); + options.Filters.Add(new AuthorizeFilter(policy)); + }) + .AddNewtonsoftJson(options => + { + options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + options.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; + options.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat; + options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc; + options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; + }); + + builder.Services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(options => + { + options.Authority = builder.Configuration.GetValue("JWT:Authority"); + options.Audience = builder.Configuration.GetValue("JWT:Audience"); + options.IncludeErrorDetails = true; + options.EventsType = typeof(HetsJwtBearerEvents); + }); + + // setup authorization + builder.Services.AddAuthorization(); + builder.Services.RegisterPermissionHandler(); + builder.Services.AddScoped(); + + // repository + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + // allow for large files to be uploaded + builder.Services.Configure(options => + { + options.MultipartBodyLengthLimit = 1073741824; // 1 GB + }); + + //enable Hangfire + builder.Services.AddHangfire(configuration => + configuration + .UseSerilogLogProvider() + .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) + .UseSimpleAssemblyNameTypeSerializer() + .UseRecommendedSerializerSettings() + .UsePostgreSqlStorage(connectionString) + ); + + builder.Services.AddHangfireServer(options => + { + options.WorkerCount = 1; + }); + + builder.Services.AddSwaggerGen(options => + { + options.SwaggerDoc("v1", new OpenApiInfo + { + Version = "v1", + Title = "HETS REST API", + Description = "Hired Equipment Tracking System" + }); + }); + + builder.Services.AddHealthChecks().AddNpgSql( + connectionString, + name: "HETS-DB-Check", + failureStatus: HealthStatus.Degraded, + tags: new string[] { "postgresql", "db" }); + + var app = builder.Build(); + + // Use services here + if (app.Environment.IsDevelopment()) + app.UseDeveloperExceptionPage(); + + app.UseMiddleware(); + + var healthCheckOptions = new HealthCheckOptions { - public static void Main(string[] args) + ResponseWriter = async (c, r) => { - CreateHostBuilder(args).Build().Run(); + c.Response.ContentType = MediaTypeNames.Application.Json; + var result = JsonSerializer.Serialize( + new + { + checks = r.Entries.Select(e => + new { + description = e.Key, + status = e.Value.Status.ToString(), + tags = e.Value.Tags, + responseTime = e.Value.Duration.TotalMilliseconds + }), + totalResponseTime = r.TotalDuration.TotalMilliseconds + }); + await c.Response.WriteAsync(result); } + }; + + app.UseHealthChecks("/healthz", healthCheckOptions); + app.UseHangfireDashboard(); + app.UseRouting(); + app.UseAuthentication(); + app.UseAuthorization(); + app.UseSerilogUi(); + app.MapControllers(); + app.UseSwagger(); + string swaggerApi = builder.Configuration.GetSection("Constants:SwaggerApiUrl").Value; + app.UseSwaggerUI(options => + { + options.SwaggerEndpoint(swaggerApi, "HETS REST API v1"); + options.DocExpansion(DocExpansion.None); + }); - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }) - .UseSerilog((hostingContext, loggerConfiguration) => - { - loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration); - }) - .ConfigureAppConfiguration((hostingContext, config) => - { - config.AddEnvironmentVariables(); - }); + app.Run(); +} +catch (Exception ex) +{ + Log.Fatal(ex, "Application terminated unexpectedly"); +} +finally +{ + Log.CloseAndFlush(); +} + +// Retrieve database connection string +string GetConnectionString(IConfiguration configuration) +{ + string connectionString; + string host = configuration["DATABASE_SERVICE_NAME"]; + string username = configuration["POSTGRESQL_USER"]; + string password = configuration["POSTGRESQL_PASSWORD"]; + string database = configuration["POSTGRESQL_DATABASE"]; + + if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(database)) + { + connectionString = configuration.GetConnectionString("HETS"); + } + else + { + // environment variables override all other settings (OpenShift) + connectionString = $"Host={host};Username={username};Password={password};Database={database}"; } + + connectionString += ";Timeout=600;CommandTimeout=0;"; + + return connectionString; } diff --git a/Server/HetsApi/Startup.cs b/Server/HetsApi/Startup.cs deleted file mode 100644 index 4f105833c..000000000 --- a/Server/HetsApi/Startup.cs +++ /dev/null @@ -1,249 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.EntityFrameworkCore; -using Microsoft.AspNetCore.Http.Features; -using Newtonsoft.Json.Serialization; -using Hangfire; -using Hangfire.PostgreSql; -using HetsApi.Authorization; -using HetsApi.Authentication; -using HetsData.Entities; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.SwaggerUI; -using HetsData.Hangfire; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.Extensions.Hosting; -using HetsApi.Middlewares; -using AutoMapper; -using HetsData.Mappings; -using HetsData.Repositories; -using Serilog.Ui.Web; -using Serilog.Ui.PostgreSqlProvider.Extensions; -using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using System.Net.Mime; -using System.Text.Json; -using System.Linq; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Diagnostics.HealthChecks; -using Microsoft.IdentityModel.Logging; - -namespace HetsApi -{ - /// - /// Application startup class - /// - public class Startup - { - public IConfiguration Configuration { get; } - - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public void ConfigureServices(IServiceCollection services) - { - IdentityModelEventSource.ShowPII = true; - string connectionString = GetConnectionString(); - - // add http context accessor - services.AddHttpContextAccessor(); - - // add auto mapper - var mappingConfig = new MapperConfiguration(cfg => - { - cfg.AddProfile(new EntityToDtoProfile()); - cfg.AddProfile(new DtoToEntityProfile()); - cfg.AddProfile(new EntityToEntityProfile()); - }); - - var mapper = mappingConfig.CreateMapper(); - services.AddSingleton(mapper); - - services.AddSerilogUi(options => options.UseNpgSql(connectionString, "het_log")); - - // add database context - services.AddDbContext(options => - { - options.UseNpgsql(connectionString, o => o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)); - options.ConfigureWarnings(o => o.Ignore(CoreEventId.RowLimitingOperationWithoutOrderByWarning)); - }); - - services.AddDbContext(options => - { - options.UseNpgsql(connectionString, o => o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)); - options.ConfigureWarnings(o => o.Ignore(CoreEventId.RowLimitingOperationWithoutOrderByWarning)); - }); - - services.AddScoped(); - - services - .AddControllers(options => - { - var policy = new AuthorizationPolicyBuilder() - .RequireAuthenticatedUser() - .Build(); - options.Filters.Add(new AuthorizeFilter(policy)); - }) - .AddNewtonsoftJson(options => - { - options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - options.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; - options.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat; - options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc; - options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; - }) - .SetCompatibilityVersion(CompatibilityVersion.Version_3_0); - - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - }) - .AddJwtBearer(options => - { - options.Authority = Configuration.GetValue("JWT:Authority"); - options.Audience = Configuration.GetValue("JWT:Audience"); - options.IncludeErrorDetails = true; - options.EventsType = typeof(HetsJwtBearerEvents); - }); - - // setup authorization - services.AddAuthorization(); - services.RegisterPermissionHandler(); - services.AddScoped(); - - // repository - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - // allow for large files to be uploaded - services.Configure(options => - { - options.MultipartBodyLengthLimit = 1073741824; // 1 GB - }); - - //enable Hangfire - services.AddHangfire(configuration => - configuration - .UseSerilogLogProvider() - .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) - .UseSimpleAssemblyNameTypeSerializer() - .UseRecommendedSerializerSettings() - .UsePostgreSqlStorage(connectionString) - ); - - services.AddHangfireServer(options => - { - options.WorkerCount = 1; - }); - - services.AddSwaggerGen(options => - { - options.SwaggerDoc("v1", new OpenApiInfo - { - Version = "v1", - Title = "HETS REST API", - Description = "Hired Equipment Tracking System" - }); - }); - - services.AddHealthChecks() - .AddNpgSql(connectionString, name: "HETS-DB-Check", failureStatus: HealthStatus.Degraded, tags: new string[] { "postgresql", "db" }); - } - - /// - /// Configure the HTTP request pipeline - /// - /// - /// - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - app.UseDeveloperExceptionPage(); - - app.UseMiddleware(); - - var healthCheckOptions = new HealthCheckOptions - { - ResponseWriter = async (c, r) => - { - c.Response.ContentType = MediaTypeNames.Application.Json; - var result = JsonSerializer.Serialize( - new - { - checks = r.Entries.Select(e => - new { - description = e.Key, - status = e.Value.Status.ToString(), - tags = e.Value.Tags, - responseTime = e.Value.Duration.TotalMilliseconds - }), - totalResponseTime = r.TotalDuration.TotalMilliseconds - }); - await c.Response.WriteAsync(result); - } - }; - - app.UseHealthChecks("/healthz", healthCheckOptions); - - app.UseHangfireDashboard(); - app.UseRouting(); - app.UseAuthentication(); - app.UseAuthorization(); - - app.UseSerilogUi(); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - }); - - app.UseSwagger(); - string swaggerApi = Configuration.GetSection("Constants:SwaggerApiUrl").Value; - app.UseSwaggerUI(options => - { - options.SwaggerEndpoint(swaggerApi, "HETS REST API v1"); - options.DocExpansion(DocExpansion.None); - }); - } - - /// - /// Retrieve database connection string - /// - /// - private string GetConnectionString() - { - string connectionString; - - string host = Configuration["DATABASE_SERVICE_NAME"]; - string username = Configuration["POSTGRESQL_USER"]; - string password = Configuration["POSTGRESQL_PASSWORD"]; - string database = Configuration["POSTGRESQL_DATABASE"]; - - if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(database)) - { - connectionString = Configuration.GetConnectionString("HETS"); - } - else - { - // environment variables override all other settings (OpenShift) - connectionString = $"Host={host};Username={username};Password={password};Database={database}"; - } - - connectionString += ";Timeout=600;CommandTimeout=0;"; - - return connectionString; - } - } -} diff --git a/Server/HetsApi/appsettings.json b/Server/HetsApi/appsettings.json index 74754c1b5..46c8f2e2a 100644 --- a/Server/HetsApi/appsettings.json +++ b/Server/HetsApi/appsettings.json @@ -13,8 +13,8 @@ "LogoffUrl-Training": "https://logontest.gov.bc.ca/clp-cgi/logoff.cgi?returl=https://trn-hets.th.gov.bc.ca&retnow=1", "LogoffUrl-UAT": "https://logontest.gov.bc.ca/clp-cgi/logoff.cgi?returl=https://uat-hets.th.gov.bc.ca&retnow=1", "LogoffUrl-Production": "https://logon.gov.bc.ca/clp-cgi/logoff.cgi?returl=https://hets.th.gov.bc.ca&retnow=1", - "Version-Application": "Release 1.10.8.0", - "Version-Database": "Release 1.10.8.0", + "Version-Application": "Release 1.10.9.0", + "Version-Database": "Release 1.10.9.0", "Maximum-Blank-Agreements": "3", "ExceptionDescriptions": { "HETS-01": "Record not found", @@ -85,7 +85,7 @@ "DumpTruck": 600 }, "ConnectionStrings": { - "HETS": "Host=localhost;Username=postgres;Password=postgres;Database=hets;Port=9000;" + "HETS": "Host=localhost;Username=postgres;Port=9000;Database=hets;" }, "JWT": { "Authority": "https://dev.loginproxy.gov.bc.ca/auth/realms/", diff --git a/Server/HetsCommon/DateUtils.cs b/Server/HetsCommon/DateUtils.cs index 4a8065da7..fdc63d2ac 100644 --- a/Server/HetsCommon/DateUtils.cs +++ b/Server/HetsCommon/DateUtils.cs @@ -18,13 +18,27 @@ public static (bool parsed, DateTime? parsedDate) ParseDate(object val) return (true, (DateTime)val); } - var formats = new string[] { "yyyyMMdd", "yyyy-MM-dd", "yyyy/MM/dd", "yyyy.MM.dd", "yyyyMd", "yyyy-M-d", "yyyy/M/dd", "yyyy.M.d" }; + var formats = new string[] { + "yyyyMMdd", + "yyyy-MM-dd", + "yyyy/MM/dd", + "yyyy.MM.dd", + "yyyyMd", + "yyyy-M-d", + "yyyy/M/dd", + "yyyy.M.d" + }; + var dateStr = val.ToString(); if (string.IsNullOrWhiteSpace(dateStr)) return (true, null); - return (DateTime.TryParseExact(dateStr, formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime parsedDate), parsedDate); + return ( + DateTime.TryParseExact( + dateStr, formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime parsedDate), + parsedDate + ); } public static string CovertToString(DateTime date) @@ -40,17 +54,9 @@ public static string CovertToString(DateTime date) /// public static DateTime ConvertUtcToPacificTime(DateTime utcDate) { - var date = ConvertTimeFromUtc(utcDate, VancouverTimeZone); - - if (date != null) - return (DateTime)date; - - date = ConvertTimeFromUtc(utcDate, PacificTimeZone); - - if (date != null) - return (DateTime)date; - - return utcDate; + return ConvertTimeFromUtc(utcDate, VancouverTimeZone) + ?? ConvertTimeFromUtc(utcDate, PacificTimeZone) + ?? utcDate; } private static DateTime? ConvertTimeFromUtc(DateTime date, string timeZoneId) @@ -68,17 +74,15 @@ public static DateTime ConvertUtcToPacificTime(DateTime utcDate) public static DateTime ConvertPacificToUtcTime(DateTime pstDate) { - var date = ConvertTimeToUtc(pstDate, VancouverTimeZone); - - if (date != null) - return (DateTime)date; - - date = ConvertTimeToUtc(pstDate, PacificTimeZone); - - if (date != null) - return (DateTime)date; + return ConvertTimeToUtc(pstDate, VancouverTimeZone) + ?? ConvertTimeToUtc(pstDate, PacificTimeZone) + ?? AsUTC(pstDate); + } - return pstDate; + public static DateTime AsUTC(DateTime dt) + { + return new DateTime( + dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, dt.Microsecond, DateTimeKind.Utc); } private static DateTime? ConvertTimeToUtc(DateTime date, string timeZoneId) @@ -96,8 +100,10 @@ public static DateTime ConvertPacificToUtcTime(DateTime pstDate) public static (DateTime utcDateFrom, DateTime utcDateTo) GetUtcDateRange(DateTime pstDateFrom, DateTime pstDateTo) { - pstDateFrom = pstDateFrom.Date; - pstDateTo = pstDateTo.Date.AddDays(1).AddSeconds(-1); + pstDateFrom = new DateTime(pstDateFrom.Year, pstDateFrom.Month, pstDateFrom.Day, 0, 0, 0, DateTimeKind.Unspecified); + pstDateTo = new DateTime(pstDateTo.Year, pstDateTo.Month, pstDateTo.Day, 0, 0, 0, DateTimeKind.Unspecified) + .AddDays(1) + .AddSeconds(-1); var utcDateFrom = ConvertPacificToUtcTime(pstDateFrom); var utcDateTo = ConvertPacificToUtcTime(pstDateTo); diff --git a/Server/HetsCommon/HetsCommon.csproj b/Server/HetsCommon/HetsCommon.csproj index 82a9f95ce..da417e9eb 100644 --- a/Server/HetsCommon/HetsCommon.csproj +++ b/Server/HetsCommon/HetsCommon.csproj @@ -1,7 +1,7 @@  - net5.0 + net7.0 Common code for the HETS application Copyright© 2017, Province of British Columbia Hets Common @@ -11,9 +11,9 @@ - - - + + + diff --git a/Server/HetsCommon/VersionInfoExtensions.cs b/Server/HetsCommon/VersionInfoExtensions.cs index 427aa6cdd..56591077a 100644 --- a/Server/HetsCommon/VersionInfoExtensions.cs +++ b/Server/HetsCommon/VersionInfoExtensions.cs @@ -41,7 +41,7 @@ public static ApplicationVersionInfo GetApplicationVersionInfo(this Assembly ass { DateTime creationTime = File.GetLastWriteTimeUtc(assembly.Location); - ApplicationVersionInfo info = new ApplicationVersionInfo() + ApplicationVersionInfo info = new() { Name = assembly.GetName().Name, Version = assembly.GetName().Version.ToString(), @@ -64,10 +64,5 @@ private static IEnumerable ToIEnumerableVersionInfo(this AssemblyNa { return assemblyNames.Select(d => new VersionInfo() { Name = d.Name, Version = d.Version.ToString() }).ToList(); } - - private static DateTime GetCreationTime(this Assembly assembly) - { - return File.GetCreationTime(assembly.Location); - } } } diff --git a/Server/HetsData/Dtos/BatchReportDto.cs b/Server/HetsData/Dtos/BatchReportDto.cs index cf54797f7..2c4ccde2f 100644 --- a/Server/HetsData/Dtos/BatchReportDto.cs +++ b/Server/HetsData/Dtos/BatchReportDto.cs @@ -10,8 +10,23 @@ public class BatchReportDto public string ReportName { get; set; } public string ReportLink { get; set; } - public DateTime? StartDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime? _startDate; + public DateTime? StartDate { + get => _startDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _startDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public bool Complete { get; set; } public int DistrictId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Dtos/BusinessUserRoleDto.cs b/Server/HetsData/Dtos/BusinessUserRoleDto.cs index bd6f22e2d..cfd9a9b4c 100644 --- a/Server/HetsData/Dtos/BusinessUserRoleDto.cs +++ b/Server/HetsData/Dtos/BusinessUserRoleDto.cs @@ -8,8 +8,20 @@ public class BusinessUserRoleDto [JsonProperty("Id")] public int BusinessUserRoleId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? ExpiryDate { get; set; } + private DateTime _effectiveDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EffectiveDate { + get => DateTime.SpecifyKind(_effectiveDate, DateTimeKind.Utc); + set => _effectiveDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _expiryDate; + public DateTime? ExpiryDate { + get => _expiryDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _expiryDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? BusinessUserId { get; set; } public int? RoleId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Dtos/DigitalFileDto.cs b/Server/HetsData/Dtos/DigitalFileDto.cs index 5c159f797..b06f36870 100644 --- a/Server/HetsData/Dtos/DigitalFileDto.cs +++ b/Server/HetsData/Dtos/DigitalFileDto.cs @@ -20,7 +20,15 @@ public class DigitalFileDto public MimeTypeDto MimeType { get; set; } public int? FileSize { get; set; } public string LastUpdateUserid { get; set; } - public DateTime? LastUpdateTimestamp { get; set; } + + private DateTime? _lastUpdateTimestamp; + public DateTime? LastUpdateTimestamp { + get => _lastUpdateTimestamp is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _lastUpdateTimestamp = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string UserName { get; set; } } } diff --git a/Server/HetsData/Dtos/DistrictDto.cs b/Server/HetsData/Dtos/DistrictDto.cs index e554137eb..1c139a087 100644 --- a/Server/HetsData/Dtos/DistrictDto.cs +++ b/Server/HetsData/Dtos/DistrictDto.cs @@ -9,8 +9,21 @@ public class DistrictDto public int DistrictId { get; set; } public int? DistrictNumber { get; set; } public string Name { get; set; } - public DateTime StartDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime _startDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime StartDate { + get => DateTime.SpecifyKind(_startDate, DateTimeKind.Utc); + set => _startDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int MinistryDistrictId { get; set; } public int? RegionId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Dtos/DistrictStatusDto.cs b/Server/HetsData/Dtos/DistrictStatusDto.cs index 00f9c5377..431170fe4 100644 --- a/Server/HetsData/Dtos/DistrictStatusDto.cs +++ b/Server/HetsData/Dtos/DistrictStatusDto.cs @@ -9,8 +9,19 @@ public class DistrictStatusDto public int DistrictId { get; set; } public int? CurrentFiscalYear { get; set; } public int? NextFiscalYear { get; set; } - public DateTime RolloverStartDate { get; set; } - public DateTime RolloverEndDate { get; set; } + + private DateTime _rolloverStartDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime RolloverStartDate { + get => DateTime.SpecifyKind(_rolloverStartDate, DateTimeKind.Utc); + set => _rolloverStartDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _rolloverEndDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime RolloverEndDate { + get => DateTime.SpecifyKind(_rolloverEndDate, DateTimeKind.Utc); + set => _rolloverEndDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public int? LocalAreaCount { get; set; } public int? DistrictEquipmentTypeCount { get; set; } public int? LocalAreaCompleteCount { get; set; } diff --git a/Server/HetsData/Dtos/EquipmentDto.cs b/Server/HetsData/Dtos/EquipmentDto.cs index 894c95e11..713973cff 100644 --- a/Server/HetsData/Dtos/EquipmentDto.cs +++ b/Server/HetsData/Dtos/EquipmentDto.cs @@ -18,14 +18,35 @@ public EquipmentDto() public string Make { get; set; } public string Model { get; set; } public string Year { get; set; } - public DateTime ReceivedDate { get; set; } + + private DateTime _receivedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime ReceivedDate { + get => DateTime.SpecifyKind(_receivedDate, DateTimeKind.Utc); + set => _receivedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public float? YearsOfService { get; set; } public string LicencePlate { get; set; } public string SerialNumber { get; set; } public string Size { get; set; } public float? Seniority { get; set; } - public DateTime? SeniorityEffectiveDate { get; set; } - public DateTime? ToDate { get; set; } + + private DateTime? _seniorityEffectiveDate; + public DateTime? SeniorityEffectiveDate { + get => _seniorityEffectiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _seniorityEffectiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _toDate; + public DateTime? ToDate { + get => _toDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _toDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? NumberInBlock { get; set; } public int? BlockNumber { get; set; } public float? ServiceHoursLastYear { get; set; } @@ -33,13 +54,35 @@ public EquipmentDto() public float? ServiceHoursTwoYearsAgo { get; set; } public bool? IsSeniorityOverridden { get; set; } public string SeniorityOverrideReason { get; set; } - public DateTime? ApprovedDate { get; set; } + + private DateTime? _approvedDate; + public DateTime? ApprovedDate { + get => _approvedDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _approvedDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int EquipmentStatusTypeId { get; set; } public string StatusComment { get; set; } - public DateTime? ArchiveDate { get; set; } + + private DateTime? _archiveDate; + public DateTime? ArchiveDate { + get => _archiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _archiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string ArchiveCode { get; set; } public string ArchiveReason { get; set; } - public DateTime LastVerifiedDate { get; set; } + + private DateTime _lastVerifiedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime LastVerifiedDate { + get => DateTime.SpecifyKind(_lastVerifiedDate, DateTimeKind.Utc); + set => _lastVerifiedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string InformationUpdateNeededReason { get; set; } public bool? IsInformationUpdateNeeded { get; set; } public int? DistrictEquipmentTypeId { get; set; } diff --git a/Server/HetsData/Dtos/HistoryDto.cs b/Server/HetsData/Dtos/HistoryDto.cs index 101dac583..fd0d659d7 100644 --- a/Server/HetsData/Dtos/HistoryDto.cs +++ b/Server/HetsData/Dtos/HistoryDto.cs @@ -7,7 +7,15 @@ public class HistoryDto { [JsonProperty("Id")] public int HistoryId { get; set; } - public DateTime? CreatedDate { get; set; } + + private DateTime? _createdDate; + public DateTime? CreatedDate { + get => _createdDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _createdDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string HistoryText { get; set; } public int? EquipmentId { get; set; } public int? OwnerId { get; set; } diff --git a/Server/HetsData/Dtos/LocalAreaDto.cs b/Server/HetsData/Dtos/LocalAreaDto.cs index 18568ce1f..84e598a62 100644 --- a/Server/HetsData/Dtos/LocalAreaDto.cs +++ b/Server/HetsData/Dtos/LocalAreaDto.cs @@ -9,8 +9,21 @@ public class LocalAreaDto public int LocalAreaId { get; set; } public int LocalAreaNumber { get; set; } public string Name { get; set; } - public DateTime? EndDate { get; set; } - public DateTime StartDate { get; set; } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime _startDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime StartDate { + get => DateTime.SpecifyKind(_startDate, DateTimeKind.Utc); + set => _startDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public int? ServiceAreaId { get; set; } public int ConcurrencyControlNumber { get; set; } public ServiceAreaDto ServiceArea { get; set; } diff --git a/Server/HetsData/Dtos/NoteDto.cs b/Server/HetsData/Dtos/NoteDto.cs index a559366a4..13080434c 100644 --- a/Server/HetsData/Dtos/NoteDto.cs +++ b/Server/HetsData/Dtos/NoteDto.cs @@ -14,7 +14,13 @@ public class NoteDto public int? ProjectId { get; set; } public int? RentalRequestId { get; set; } public int ConcurrencyControlNumber { get; set; } + + private DateTime _dbCreateTimeStamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + [JsonProperty("createDate")] - public DateTime DbCreateTimeStamp { get; set; } + public DateTime DbCreateTimeStamp { + get => DateTime.SpecifyKind(_dbCreateTimeStamp, DateTimeKind.Utc); + set => _dbCreateTimeStamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } } } diff --git a/Server/HetsData/Dtos/OwnerDto.cs b/Server/HetsData/Dtos/OwnerDto.cs index ae7820b1a..8fddbddf5 100644 --- a/Server/HetsData/Dtos/OwnerDto.cs +++ b/Server/HetsData/Dtos/OwnerDto.cs @@ -27,16 +27,40 @@ public OwnerDto() public string Province { get; set; } public int OwnerStatusTypeId { get; set; } public string StatusComment { get; set; } - public DateTime? ArchiveDate { get; set; } + + private DateTime? _archiveDate; + public DateTime? ArchiveDate { + get => _archiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _archiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string ArchiveCode { get; set; } public string ArchiveReason { get; set; } public int? LocalAreaId { get; set; } public int? PrimaryContactId { get; set; } public string CglCompany { get; set; } public string CglPolicyNumber { get; set; } - public DateTime? CglendDate { get; set; } + + private DateTime? _cglendDate; + public DateTime? CglendDate { + get => _cglendDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _cglendDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string WorkSafeBcpolicyNumber { get; set; } - public DateTime? WorkSafeBcexpiryDate { get; set; } + + private DateTime? _workSafeBcexpiryDate; + public DateTime? WorkSafeBcexpiryDate { + get => _workSafeBcexpiryDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _workSafeBcexpiryDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public bool? IsMaintenanceContractor { get; set; } public bool MeetsResidency { get; set; } public int? BusinessId { get; set; } diff --git a/Server/HetsData/Dtos/ProjectDto.cs b/Server/HetsData/Dtos/ProjectDto.cs index d07d8f693..70effcc79 100644 --- a/Server/HetsData/Dtos/ProjectDto.cs +++ b/Server/HetsData/Dtos/ProjectDto.cs @@ -38,7 +38,11 @@ public ProjectDto() public bool CanEditStatus { get; set; } public string Status { get; set; } - public DateTime FiscalYearStartDate { get; set; } + private DateTime _fiscalYearStartDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime FiscalYearStartDate { + get => DateTime.SpecifyKind(_fiscalYearStartDate, DateTimeKind.Utc); + set => _fiscalYearStartDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } } } diff --git a/Server/HetsData/Dtos/RegionDto.cs b/Server/HetsData/Dtos/RegionDto.cs index 0d8f03934..0d24811bc 100644 --- a/Server/HetsData/Dtos/RegionDto.cs +++ b/Server/HetsData/Dtos/RegionDto.cs @@ -10,8 +10,21 @@ public class RegionDto public string Name { get; set; } public int? RegionNumber { get; set; } public int MinistryRegionId { get; set; } - public DateTime StartDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime _startDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime StartDate { + get => DateTime.SpecifyKind(_startDate, DateTimeKind.Utc); + set => _startDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int ConcurrencyControlNumber { get; set; } } } diff --git a/Server/HetsData/Dtos/RentalAgreementDto.cs b/Server/HetsData/Dtos/RentalAgreementDto.cs index 3ad8b2e1f..712b7da30 100644 --- a/Server/HetsData/Dtos/RentalAgreementDto.cs +++ b/Server/HetsData/Dtos/RentalAgreementDto.cs @@ -17,12 +17,28 @@ public RentalAgreementDto() public int RentalAgreementId { get; set; } public string Number { get; set; } public int? EstimateHours { get; set; } - public DateTime? EstimateStartWork { get; set; } + + private DateTime? _estimateStartWork; + public DateTime? EstimateStartWork { + get => _estimateStartWork is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _estimateStartWork = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string Note { get; set; } public float? EquipmentRate { get; set; } public string RateComment { get; set; } public int RatePeriodTypeId { get; set; } - public DateTime? DatedOn { get; set; } + + private DateTime? _datedOn; + public DateTime? DatedOn { + get => _datedOn is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _datedOn = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string AgreementCity { get; set; } public int RentalAgreementStatusTypeId { get; set; } public int? EquipmentId { get; set; } diff --git a/Server/HetsData/Dtos/RentalRequestDto.cs b/Server/HetsData/Dtos/RentalRequestDto.cs index ebe42a697..51c00ab4c 100644 --- a/Server/HetsData/Dtos/RentalRequestDto.cs +++ b/Server/HetsData/Dtos/RentalRequestDto.cs @@ -15,8 +15,23 @@ public RentalRequestDto() [JsonProperty("Id")] public int RentalRequestId { get; set; } public int EquipmentCount { get; set; } - public DateTime? ExpectedStartDate { get; set; } - public DateTime? ExpectedEndDate { get; set; } + + private DateTime? _expectedStartDate; + public DateTime? ExpectedStartDate { + get => _expectedStartDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _expectedStartDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _expectedEndDate; + public DateTime? ExpectedEndDate { + get => _expectedEndDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _expectedEndDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? ExpectedHours { get; set; } public int? FirstOnRotationListId { get; set; } public int RentalRequestStatusTypeId { get; set; } diff --git a/Server/HetsData/Dtos/RentalRequestRotationListDto.cs b/Server/HetsData/Dtos/RentalRequestRotationListDto.cs index 79cb745ca..09577ac77 100644 --- a/Server/HetsData/Dtos/RentalRequestRotationListDto.cs +++ b/Server/HetsData/Dtos/RentalRequestRotationListDto.cs @@ -14,12 +14,28 @@ public RentalRequestRotationListDto() [JsonProperty("Id")] public int RentalRequestRotationListId { get; set; } public int RotationListSortOrder { get; set; } - public DateTime? AskedDateTime { get; set; } + + private DateTime? _askedDateTime; + public DateTime? AskedDateTime { + get => _askedDateTime is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _askedDateTime = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public bool? WasAsked { get; set; } public string OfferResponse { get; set; } public string OfferResponseNote { get; set; } public string OfferRefusalReason { get; set; } - public DateTime? OfferResponseDatetime { get; set; } + + private DateTime? _offerResponseDatetime; + public DateTime? OfferResponseDatetime { + get => _offerResponseDatetime is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _offerResponseDatetime = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public bool? IsForceHire { get; set; } public string Note { get; set; } public int? EquipmentId { get; set; } diff --git a/Server/HetsData/Dtos/RentalRequestSeniorityListDto.cs b/Server/HetsData/Dtos/RentalRequestSeniorityListDto.cs index 95bd00021..fb684c166 100644 --- a/Server/HetsData/Dtos/RentalRequestSeniorityListDto.cs +++ b/Server/HetsData/Dtos/RentalRequestSeniorityListDto.cs @@ -12,14 +12,35 @@ public class RentalRequestSeniorityListDto public string Make { get; set; } public string Model { get; set; } public string Year { get; set; } - public DateTime ReceivedDate { get; set; } + + private DateTime _receivedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime ReceivedDate { + get => DateTime.SpecifyKind(_receivedDate, DateTimeKind.Utc); + set => _receivedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public float? YearsOfService { get; set; } public string LicencePlate { get; set; } public string SerialNumber { get; set; } public string Size { get; set; } public float? Seniority { get; set; } - public DateTime? SeniorityEffectiveDate { get; set; } - public DateTime? ToDate { get; set; } + + private DateTime? _seniorityEffectiveDate; + public DateTime? SeniorityEffectiveDate { + get => _seniorityEffectiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _seniorityEffectiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _toDate; + public DateTime? ToDate { + get => _toDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _toDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? NumberInBlock { get; set; } public int? BlockNumber { get; set; } public float? ServiceHoursLastYear { get; set; } @@ -27,13 +48,35 @@ public class RentalRequestSeniorityListDto public float? ServiceHoursTwoYearsAgo { get; set; } public bool? IsSeniorityOverridden { get; set; } public string SeniorityOverrideReason { get; set; } - public DateTime? ApprovedDate { get; set; } + + private DateTime? _approvedDate; + public DateTime? ApprovedDate { + get => _approvedDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _approvedDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int EquipmentStatusTypeId { get; set; } public string StatusComment { get; set; } - public DateTime? ArchiveDate { get; set; } + + private DateTime? _archiveDate; + public DateTime? ArchiveDate { + get => _archiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _archiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string ArchiveCode { get; set; } public string ArchiveReason { get; set; } - public DateTime LastVerifiedDate { get; set; } + + private DateTime _lastVerifiedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime LastVerifiedDate { + get => DateTime.SpecifyKind(_lastVerifiedDate, DateTimeKind.Utc); + set => _lastVerifiedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string InformationUpdateNeededReason { get; set; } public bool? IsInformationUpdateNeeded { get; set; } public int? DistrictEquipmentTypeId { get; set; } diff --git a/Server/HetsData/Dtos/ServiceAreaDto.cs b/Server/HetsData/Dtos/ServiceAreaDto.cs index e8d58f3f2..a54573e5c 100644 --- a/Server/HetsData/Dtos/ServiceAreaDto.cs +++ b/Server/HetsData/Dtos/ServiceAreaDto.cs @@ -10,8 +10,21 @@ public class ServiceAreaDto public string Name { get; set; } public int? AreaNumber { get; set; } public int MinistryServiceAreaId { get; set; } - public DateTime FiscalStartDate { get; set; } - public DateTime? FiscalEndDate { get; set; } + + private DateTime _fiscalStartDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime FiscalStartDate { + get => DateTime.SpecifyKind(_fiscalStartDate, DateTimeKind.Utc); + set => _fiscalStartDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _fiscalEndDate; + public DateTime? FiscalEndDate { + get => _fiscalEndDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _fiscalEndDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string Address { get; set; } public string Phone { get; set; } public string Fax { get; set; } diff --git a/Server/HetsData/Dtos/TimeRecordDto.cs b/Server/HetsData/Dtos/TimeRecordDto.cs index d424fdc7b..4796148cf 100644 --- a/Server/HetsData/Dtos/TimeRecordDto.cs +++ b/Server/HetsData/Dtos/TimeRecordDto.cs @@ -7,8 +7,21 @@ public class TimeRecordDto { [JsonProperty("Id")] public int TimeRecordId { get; set; } - public DateTime? EnteredDate { get; set; } - public DateTime WorkedDate { get; set; } + + private DateTime? _enteredDate; + public DateTime? EnteredDate { + get => _enteredDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _enteredDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime _workedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime WorkedDate { + get => DateTime.SpecifyKind(_workedDate, DateTimeKind.Utc); + set => _workedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public int TimePeriodTypeId { get; set; } public float? Hours { get; set; } public int? RentalAgreementRateId { get; set; } diff --git a/Server/HetsData/Dtos/UserRoleDto.cs b/Server/HetsData/Dtos/UserRoleDto.cs index 6f7a879fb..105b85a89 100644 --- a/Server/HetsData/Dtos/UserRoleDto.cs +++ b/Server/HetsData/Dtos/UserRoleDto.cs @@ -7,8 +7,21 @@ public class UserRoleDto { [JsonProperty("Id")] public int UserRoleId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? ExpiryDate { get; set; } + + private DateTime _effectiveDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EffectiveDate { + get => DateTime.SpecifyKind(_effectiveDate, DateTimeKind.Utc); + set => _effectiveDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _expiryDate; + public DateTime? ExpiryDate { + get => _expiryDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _expiryDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? UserId { get; set; } public int? RoleId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/DbAppContextExtension.cs b/Server/HetsData/Entities/DbAppContextExtension.cs index 8a63c7e2a..1d9203add 100644 --- a/Server/HetsData/Entities/DbAppContextExtension.cs +++ b/Server/HetsData/Entities/DbAppContextExtension.cs @@ -1,8 +1,10 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; +using HetsCommon; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.Extensions.Logging; @@ -44,7 +46,7 @@ public int SaveChangesForImport() else { int controlNumber = (int)GetAuditProperty(entry.Entity, "ConcurrencyControlNumber"); - controlNumber = controlNumber + 1; + controlNumber++; SetAuditProperty(entry.Entity, "ConcurrencyControlNumber", controlNumber); } } @@ -114,6 +116,7 @@ private static void SetAuditProperty(object obj, string property, object value) /// public override int SaveChanges() { + // get all of the modified records List modifiedEntries = ChangeTracker.Entries() .Where(e => e.State == EntityState.Added || @@ -123,7 +126,7 @@ public override int SaveChanges() // manage the audit columns and the concurrency column DateTime currentTime = DateTime.UtcNow; - List seniorityAudits = new List(); + List seniorityAudits = new(); foreach (EntityEntry entry in modifiedEntries) { @@ -133,19 +136,19 @@ public override int SaveChanges() SetAuditProperty(entry.Entity, "AppLastUpdateUserDirectory", DirectoryName); SetAuditProperty(entry.Entity, "AppLastUpdateUserGuid", SmUserGuid); SetAuditProperty(entry.Entity, "AppLastUpdateTimestamp", currentTime); - + if (entry.State == EntityState.Added) { SetAuditProperty(entry.Entity, "AppCreateUserid", SmUserId); SetAuditProperty(entry.Entity, "AppCreateUserDirectory", DirectoryName); SetAuditProperty(entry.Entity, "AppCreateUserGuid", SmUserGuid); SetAuditProperty(entry.Entity, "AppCreateTimestamp", currentTime); - SetAuditProperty(entry.Entity, "ConcurrencyControlNumber", 1); + SetAuditProperty(entry.Entity, "ConcurrencyControlNumber", 1); } else { int controlNumber = (int)GetAuditProperty(entry.Entity, "ConcurrencyControlNumber"); - controlNumber = controlNumber + 1; + controlNumber++; SetAuditProperty(entry.Entity, "ConcurrencyControlNumber", controlNumber); } } @@ -229,7 +232,7 @@ private void DoEquipmentAudit(List audits, EntityEntry entry, DateTime currentTime = DateTime.UtcNow; // create the audit entry. - HetSeniorityAudit seniorityAudit = new HetSeniorityAudit + HetSeniorityAudit seniorityAudit = new() { BlockNumber = original.BlockNumber, EndDate = currentTime @@ -243,7 +246,6 @@ private void DoEquipmentAudit(List audits, EntityEntry entry, seniorityAudit.AppLastUpdateTimestamp = currentTime; seniorityAudit.AppCreateUserid = smUserId; seniorityAudit.AppLastUpdateUserid = smUserId; - seniorityAudit.EquipmentId = tempChangedId; seniorityAudit.LocalAreaId = tempLocalAreaId; seniorityAudit.OwnerId = tempOwnerId; @@ -253,9 +255,9 @@ private void DoEquipmentAudit(List audits, EntityEntry entry, seniorityAudit.OwnerOrganizationName = seniorityAudit.Owner.OrganizationName; } - if (original.SeniorityEffectiveDate != null) + if (original.SeniorityEffectiveDate is DateTime seniorityEffectiveDateUtc) { - seniorityAudit.StartDate = (DateTime)original.SeniorityEffectiveDate; + seniorityAudit.StartDate = DateUtils.AsUTC(seniorityEffectiveDateUtc); } seniorityAudit.Seniority = original.Seniority; diff --git a/Server/HetsData/Entities/HetBatchReport.cs b/Server/HetsData/Entities/HetBatchReport.cs index 4504482f3..dcc4653d9 100644 --- a/Server/HetsData/Entities/HetBatchReport.cs +++ b/Server/HetsData/Entities/HetBatchReport.cs @@ -10,21 +10,59 @@ public partial class HetBatchReport public int ReportId { get; set; } public string ReportName { get; set; } public string ReportLink { get; set; } - public DateTime? StartDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime? _startDate; + public DateTime? StartDate { + get => _startDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _startDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public bool? Complete { get; set; } public int DistrictId { get; set; } public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetBusiness.cs b/Server/HetsData/Entities/HetBusiness.cs index ee3bccf8a..3a0133568 100644 --- a/Server/HetsData/Entities/HetBusiness.cs +++ b/Server/HetsData/Entities/HetBusiness.cs @@ -21,14 +21,37 @@ public HetBusiness() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetBusinessUser.cs b/Server/HetsData/Entities/HetBusinessUser.cs index fdeee23c4..c9b192c47 100644 --- a/Server/HetsData/Entities/HetBusinessUser.cs +++ b/Server/HetsData/Entities/HetBusinessUser.cs @@ -24,14 +24,37 @@ public HetBusinessUser() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetBusinessUserRole.cs b/Server/HetsData/Entities/HetBusinessUserRole.cs index c01d1209f..097b14ea2 100644 --- a/Server/HetsData/Entities/HetBusinessUserRole.cs +++ b/Server/HetsData/Entities/HetBusinessUserRole.cs @@ -8,21 +8,57 @@ namespace HetsData.Entities public partial class HetBusinessUserRole { public int BusinessUserRoleId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? ExpiryDate { get; set; } + + private DateTime _effectiveDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EffectiveDate { + get => DateTime.SpecifyKind(_effectiveDate, DateTimeKind.Utc); + set => _effectiveDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _expiryDate; + public DateTime? ExpiryDate { + get => _expiryDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _expiryDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? BusinessUserId { get; set; } public int? RoleId { get; set; } public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetConditionType.cs b/Server/HetsData/Entities/HetConditionType.cs index d8828cef8..23ad4a3b6 100644 --- a/Server/HetsData/Entities/HetConditionType.cs +++ b/Server/HetsData/Entities/HetConditionType.cs @@ -15,14 +15,37 @@ public partial class HetConditionType public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetContact.cs b/Server/HetsData/Entities/HetContact.cs index aa40af41e..a2a02b194 100644 --- a/Server/HetsData/Entities/HetContact.cs +++ b/Server/HetsData/Entities/HetContact.cs @@ -32,14 +32,37 @@ public HetContact() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetDigitalFile.cs b/Server/HetsData/Entities/HetDigitalFile.cs index bb88f7095..623f98c4a 100644 --- a/Server/HetsData/Entities/HetDigitalFile.cs +++ b/Server/HetsData/Entities/HetDigitalFile.cs @@ -20,14 +20,37 @@ public partial class HetDigitalFile public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetDistrict.cs b/Server/HetsData/Entities/HetDistrict.cs index a4d464637..75bbd1e9d 100644 --- a/Server/HetsData/Entities/HetDistrict.cs +++ b/Server/HetsData/Entities/HetDistrict.cs @@ -23,21 +23,57 @@ public HetDistrict() public int DistrictId { get; set; } public int? DistrictNumber { get; set; } public string Name { get; set; } - public DateTime StartDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime _startDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime StartDate { + get => DateTime.SpecifyKind(_startDate, DateTimeKind.Utc); + set => _startDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int MinistryDistrictId { get; set; } public int? RegionId { get; set; } public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetDistrictEquipmentType.cs b/Server/HetsData/Entities/HetDistrictEquipmentType.cs index f7af0e514..500a6f360 100644 --- a/Server/HetsData/Entities/HetDistrictEquipmentType.cs +++ b/Server/HetsData/Entities/HetDistrictEquipmentType.cs @@ -21,14 +21,37 @@ public HetDistrictEquipmentType() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } public bool Deleted { get; set; } diff --git a/Server/HetsData/Entities/HetDistrictStatus.cs b/Server/HetsData/Entities/HetDistrictStatus.cs index 8c500e9e8..d0c87df91 100644 --- a/Server/HetsData/Entities/HetDistrictStatus.cs +++ b/Server/HetsData/Entities/HetDistrictStatus.cs @@ -10,8 +10,23 @@ public partial class HetDistrictStatus public int DistrictId { get; set; } public int? CurrentFiscalYear { get; set; } public int? NextFiscalYear { get; set; } - public DateTime? RolloverStartDate { get; set; } - public DateTime? RolloverEndDate { get; set; } + + private DateTime? _rolloverStartDate; + public DateTime? RolloverStartDate { + get => _rolloverStartDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _rolloverStartDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _rolloverEndDate; + public DateTime? RolloverEndDate { + get => _rolloverEndDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _rolloverEndDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? LocalAreaCount { get; set; } public int? DistrictEquipmentTypeCount { get; set; } public int? LocalAreaCompleteCount { get; set; } @@ -21,14 +36,37 @@ public partial class HetDistrictStatus public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetEquipment.cs b/Server/HetsData/Entities/HetEquipment.cs index 3a4294a7f..38ef312f8 100644 --- a/Server/HetsData/Entities/HetEquipment.cs +++ b/Server/HetsData/Entities/HetEquipment.cs @@ -26,14 +26,35 @@ public HetEquipment() public string Make { get; set; } public string Model { get; set; } public string Year { get; set; } - public DateTime ReceivedDate { get; set; } + + private DateTime _receivedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime ReceivedDate { + get => DateTime.SpecifyKind(_receivedDate, DateTimeKind.Utc); + set => _receivedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public float? YearsOfService { get; set; } public string LicencePlate { get; set; } public string SerialNumber { get; set; } public string Size { get; set; } public float? Seniority { get; set; } - public DateTime? SeniorityEffectiveDate { get; set; } - public DateTime? ToDate { get; set; } + + private DateTime? _seniorityEffectiveDate; + public DateTime? SeniorityEffectiveDate { + get => _seniorityEffectiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _seniorityEffectiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _toDate; + public DateTime? ToDate { + get => _toDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _toDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? NumberInBlock { get; set; } public int? BlockNumber { get; set; } public float? ServiceHoursLastYear { get; set; } @@ -41,13 +62,35 @@ public HetEquipment() public float? ServiceHoursTwoYearsAgo { get; set; } public bool? IsSeniorityOverridden { get; set; } public string SeniorityOverrideReason { get; set; } - public DateTime? ApprovedDate { get; set; } + + private DateTime? _approvedDate; + public DateTime? ApprovedDate { + get => _approvedDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _approvedDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int EquipmentStatusTypeId { get; set; } public string StatusComment { get; set; } - public DateTime? ArchiveDate { get; set; } + + private DateTime? _archiveDate; + public DateTime? ArchiveDate { + get => _archiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _archiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string ArchiveCode { get; set; } public string ArchiveReason { get; set; } - public DateTime LastVerifiedDate { get; set; } + + private DateTime _lastVerifiedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime LastVerifiedDate { + get => DateTime.SpecifyKind(_lastVerifiedDate, DateTimeKind.Utc); + set => _lastVerifiedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string InformationUpdateNeededReason { get; set; } public bool? IsInformationUpdateNeeded { get; set; } public int? DistrictEquipmentTypeId { get; set; } @@ -62,14 +105,37 @@ public HetEquipment() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetEquipmentAttachment.cs b/Server/HetsData/Entities/HetEquipmentAttachment.cs index 89522328e..90b2ecdd7 100644 --- a/Server/HetsData/Entities/HetEquipmentAttachment.cs +++ b/Server/HetsData/Entities/HetEquipmentAttachment.cs @@ -14,14 +14,37 @@ public partial class HetEquipmentAttachment public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetEquipmentAttachmentHist.cs b/Server/HetsData/Entities/HetEquipmentAttachmentHist.cs index 0f487712f..10a2f3a63 100644 --- a/Server/HetsData/Entities/HetEquipmentAttachmentHist.cs +++ b/Server/HetsData/Entities/HetEquipmentAttachmentHist.cs @@ -8,8 +8,21 @@ namespace HetsData.Entities public partial class HetEquipmentAttachmentHist { public int EquipmentAttachmentHistId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime _effectiveDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EffectiveDate { + get => DateTime.SpecifyKind(_effectiveDate, DateTimeKind.Utc); + set => _effectiveDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int EquipmentAttachmentId { get; set; } public string TypeName { get; set; } public string Description { get; set; } @@ -17,14 +30,37 @@ public partial class HetEquipmentAttachmentHist public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } } diff --git a/Server/HetsData/Entities/HetEquipmentHist.cs b/Server/HetsData/Entities/HetEquipmentHist.cs index 2e291a56e..3c3413c2d 100644 --- a/Server/HetsData/Entities/HetEquipmentHist.cs +++ b/Server/HetsData/Entities/HetEquipmentHist.cs @@ -8,22 +8,56 @@ namespace HetsData.Entities public partial class HetEquipmentHist { public int EquipmentHistId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime _effectiveDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EffectiveDate { + get => DateTime.SpecifyKind(_effectiveDate, DateTimeKind.Utc); + set => _effectiveDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _EndDate; + public DateTime? EndDate { + get => _EndDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _EndDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int EquipmentId { get; set; } public string Type { get; set; } public string EquipmentCode { get; set; } public string Make { get; set; } public string Model { get; set; } public string Year { get; set; } - public DateTime ReceivedDate { get; set; } + + private DateTime _receivedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime ReceivedDate { + get => DateTime.SpecifyKind(_receivedDate, DateTimeKind.Utc); + set => _receivedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public float? YearsOfService { get; set; } public string LicencePlate { get; set; } public string SerialNumber { get; set; } public string Size { get; set; } public float? Seniority { get; set; } - public DateTime? SeniorityEffectiveDate { get; set; } - public DateTime? ToDate { get; set; } + + private DateTime? _seniorityEffectiveDate; + public DateTime? SeniorityEffectiveDate { + get => _seniorityEffectiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _seniorityEffectiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _toDate; + public DateTime? ToDate { + get => _toDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _toDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? NumberInBlock { get; set; } public int? BlockNumber { get; set; } public float? ServiceHoursLastYear { get; set; } @@ -31,13 +65,35 @@ public partial class HetEquipmentHist public float? ServiceHoursTwoYearsAgo { get; set; } public bool? IsSeniorityOverridden { get; set; } public string SeniorityOverrideReason { get; set; } - public DateTime? ApprovedDate { get; set; } + + private DateTime? _approvedDate; + public DateTime? ApprovedDate { + get => _approvedDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _approvedDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int EquipmentStatusTypeId { get; set; } public string StatusComment { get; set; } - public DateTime? ArchiveDate { get; set; } + + private DateTime? _archiveDate; + public DateTime? ArchiveDate { + get => _archiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _archiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string ArchiveCode { get; set; } public string ArchiveReason { get; set; } - public DateTime LastVerifiedDate { get; set; } + + private DateTime _lastVerifiedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime LastVerifiedDate { + get => DateTime.SpecifyKind(_lastVerifiedDate, DateTimeKind.Utc); + set => _lastVerifiedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string InformationUpdateNeededReason { get; set; } public bool? IsInformationUpdateNeeded { get; set; } public int? DistrictEquipmentTypeId { get; set; } @@ -52,14 +108,37 @@ public partial class HetEquipmentHist public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } } diff --git a/Server/HetsData/Entities/HetEquipmentStatusType.cs b/Server/HetsData/Entities/HetEquipmentStatusType.cs index f5e154bde..c9a6890c0 100644 --- a/Server/HetsData/Entities/HetEquipmentStatusType.cs +++ b/Server/HetsData/Entities/HetEquipmentStatusType.cs @@ -22,14 +22,37 @@ public HetEquipmentStatusType() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetEquipmentType.cs b/Server/HetsData/Entities/HetEquipmentType.cs index 0a015ed71..5db9d8c1d 100644 --- a/Server/HetsData/Entities/HetEquipmentType.cs +++ b/Server/HetsData/Entities/HetEquipmentType.cs @@ -24,14 +24,37 @@ public HetEquipmentType() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetHistory.cs b/Server/HetsData/Entities/HetHistory.cs index c0c243fc2..faf37da95 100644 --- a/Server/HetsData/Entities/HetHistory.cs +++ b/Server/HetsData/Entities/HetHistory.cs @@ -8,7 +8,15 @@ namespace HetsData.Entities public partial class HetHistory { public int HistoryId { get; set; } - public DateTime? CreatedDate { get; set; } + + private DateTime? _createdDate; + public DateTime? CreatedDate { + get => _createdDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _createdDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string HistoryText { get; set; } public int? EquipmentId { get; set; } public int? OwnerId { get; set; } @@ -17,14 +25,37 @@ public partial class HetHistory public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetLocalArea.cs b/Server/HetsData/Entities/HetLocalArea.cs index 0ea48939a..79791c512 100644 --- a/Server/HetsData/Entities/HetLocalArea.cs +++ b/Server/HetsData/Entities/HetLocalArea.cs @@ -19,20 +19,56 @@ public HetLocalArea() public int LocalAreaId { get; set; } public int LocalAreaNumber { get; set; } public string Name { get; set; } - public DateTime? EndDate { get; set; } - public DateTime StartDate { get; set; } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime _startDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime StartDate { + get => DateTime.SpecifyKind(_startDate, DateTimeKind.Utc); + set => _startDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public int? ServiceAreaId { get; set; } public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetLog.cs b/Server/HetsData/Entities/HetLog.cs index 5f7973e08..f5460635c 100644 --- a/Server/HetsData/Entities/HetLog.cs +++ b/Server/HetsData/Entities/HetLog.cs @@ -14,6 +14,13 @@ public partial class HetLog public string Message { get; set; } public string MessageTemplate { get; set; } public string PropsTest { get; set; } - public DateTime? Timestamp { get; set; } + + private DateTime? _timestamp; + public DateTime? Timestamp { + get => _timestamp is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _timestamp = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } } } diff --git a/Server/HetsData/Entities/HetMimeType.cs b/Server/HetsData/Entities/HetMimeType.cs index c6dc14f25..0484cca52 100644 --- a/Server/HetsData/Entities/HetMimeType.cs +++ b/Server/HetsData/Entities/HetMimeType.cs @@ -21,14 +21,37 @@ public HetMimeType() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetNote.cs b/Server/HetsData/Entities/HetNote.cs index ef0adadc9..9f350fdde 100644 --- a/Server/HetsData/Entities/HetNote.cs +++ b/Server/HetsData/Entities/HetNote.cs @@ -17,14 +17,37 @@ public partial class HetNote public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetNoteHist.cs b/Server/HetsData/Entities/HetNoteHist.cs index 35eeed910..340651e12 100644 --- a/Server/HetsData/Entities/HetNoteHist.cs +++ b/Server/HetsData/Entities/HetNoteHist.cs @@ -9,8 +9,21 @@ public partial class HetNoteHist { public int NoteHistId { get; set; } public int NoteId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime _effectiveDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EffectiveDate { + get => DateTime.SpecifyKind(_effectiveDate, DateTimeKind.Utc); + set => _effectiveDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string Text { get; set; } public bool? IsNoLongerRelevant { get; set; } public int? EquipmentId { get; set; } @@ -20,14 +33,37 @@ public partial class HetNoteHist public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } } diff --git a/Server/HetsData/Entities/HetOwner.cs b/Server/HetsData/Entities/HetOwner.cs index cd0b6e6a3..bece0f514 100644 --- a/Server/HetsData/Entities/HetOwner.cs +++ b/Server/HetsData/Entities/HetOwner.cs @@ -32,16 +32,40 @@ public HetOwner() public string Province { get; set; } public int OwnerStatusTypeId { get; set; } public string StatusComment { get; set; } - public DateTime? ArchiveDate { get; set; } + + private DateTime? _archiveDate; + public DateTime? ArchiveDate { + get => _archiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _archiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string ArchiveCode { get; set; } public string ArchiveReason { get; set; } public int? LocalAreaId { get; set; } public int? PrimaryContactId { get; set; } public string CglCompany { get; set; } public string CglPolicyNumber { get; set; } - public DateTime? CglendDate { get; set; } + + private DateTime? _cglendDate; + public DateTime? CglendDate { + get => _cglendDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _cglendDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string WorkSafeBcpolicyNumber { get; set; } - public DateTime? WorkSafeBcexpiryDate { get; set; } + + private DateTime? _workSafeBcexpiryDate; + public DateTime? WorkSafeBcexpiryDate { + get => _workSafeBcexpiryDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _workSafeBcexpiryDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public bool? IsMaintenanceContractor { get; set; } public bool MeetsResidency { get; set; } public int? BusinessId { get; set; } @@ -49,14 +73,37 @@ public HetOwner() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetOwnerStatusType.cs b/Server/HetsData/Entities/HetOwnerStatusType.cs index 9c665e7d6..5b6cff22b 100644 --- a/Server/HetsData/Entities/HetOwnerStatusType.cs +++ b/Server/HetsData/Entities/HetOwnerStatusType.cs @@ -21,14 +21,37 @@ public HetOwnerStatusType() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetPermission.cs b/Server/HetsData/Entities/HetPermission.cs index 914dc1347..1ba4e051e 100644 --- a/Server/HetsData/Entities/HetPermission.cs +++ b/Server/HetsData/Entities/HetPermission.cs @@ -19,14 +19,37 @@ public HetPermission() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetProject.cs b/Server/HetsData/Entities/HetProject.cs index 0590ac460..4b6e66a1e 100644 --- a/Server/HetsData/Entities/HetProject.cs +++ b/Server/HetsData/Entities/HetProject.cs @@ -27,14 +27,37 @@ public HetProject() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } public string FiscalYear { get; set; } diff --git a/Server/HetsData/Entities/HetProjectStatusType.cs b/Server/HetsData/Entities/HetProjectStatusType.cs index 63df8c7d5..8fc1a90ab 100644 --- a/Server/HetsData/Entities/HetProjectStatusType.cs +++ b/Server/HetsData/Entities/HetProjectStatusType.cs @@ -21,14 +21,37 @@ public HetProjectStatusType() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetProvincialRateType.cs b/Server/HetsData/Entities/HetProvincialRateType.cs index 34db37608..7e270899d 100644 --- a/Server/HetsData/Entities/HetProvincialRateType.cs +++ b/Server/HetsData/Entities/HetProvincialRateType.cs @@ -20,14 +20,37 @@ public partial class HetProvincialRateType public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } } diff --git a/Server/HetsData/Entities/HetRatePeriodType.cs b/Server/HetsData/Entities/HetRatePeriodType.cs index b7d04c4da..ea0a2e27c 100644 --- a/Server/HetsData/Entities/HetRatePeriodType.cs +++ b/Server/HetsData/Entities/HetRatePeriodType.cs @@ -22,14 +22,37 @@ public HetRatePeriodType() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetRegion.cs b/Server/HetsData/Entities/HetRegion.cs index 826711390..6fc405238 100644 --- a/Server/HetsData/Entities/HetRegion.cs +++ b/Server/HetsData/Entities/HetRegion.cs @@ -16,19 +16,55 @@ public HetRegion() public string Name { get; set; } public int? RegionNumber { get; set; } public int MinistryRegionId { get; set; } - public DateTime StartDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime _startDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime StartDate { + get => DateTime.SpecifyKind(_startDate, DateTimeKind.Utc); + set => _startDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetRentalAgreement.cs b/Server/HetsData/Entities/HetRentalAgreement.cs index d1fec711c..db6039d4d 100644 --- a/Server/HetsData/Entities/HetRentalAgreement.cs +++ b/Server/HetsData/Entities/HetRentalAgreement.cs @@ -18,12 +18,28 @@ public HetRentalAgreement() public int RentalAgreementId { get; set; } public string Number { get; set; } public int? EstimateHours { get; set; } - public DateTime? EstimateStartWork { get; set; } + + private DateTime? _estimateStartWork; + public DateTime? EstimateStartWork { + get => _estimateStartWork is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _estimateStartWork = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string Note { get; set; } public float? EquipmentRate { get; set; } public string RateComment { get; set; } public int RatePeriodTypeId { get; set; } - public DateTime? DatedOn { get; set; } + + private DateTime? _datedOn; + public DateTime? DatedOn { + get => _datedOn is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _datedOn = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int RentalAgreementStatusTypeId { get; set; } public int? EquipmentId { get; set; } public int? ProjectId { get; set; } @@ -33,14 +49,37 @@ public HetRentalAgreement() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } public string AgreementCity { get; set; } diff --git a/Server/HetsData/Entities/HetRentalAgreementCondition.cs b/Server/HetsData/Entities/HetRentalAgreementCondition.cs index a13b2fafe..52af2fbb2 100644 --- a/Server/HetsData/Entities/HetRentalAgreementCondition.cs +++ b/Server/HetsData/Entities/HetRentalAgreementCondition.cs @@ -14,14 +14,37 @@ public partial class HetRentalAgreementCondition public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetRentalAgreementConditionHist.cs b/Server/HetsData/Entities/HetRentalAgreementConditionHist.cs index 1ea9f5377..88bfbcd4e 100644 --- a/Server/HetsData/Entities/HetRentalAgreementConditionHist.cs +++ b/Server/HetsData/Entities/HetRentalAgreementConditionHist.cs @@ -9,22 +9,58 @@ public partial class HetRentalAgreementConditionHist { public int RentalAgreementConditionHistId { get; set; } public int RentalAgreementConditionId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime _effectiveDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EffectiveDate { + get => DateTime.SpecifyKind(_effectiveDate, DateTimeKind.Utc); + set => _effectiveDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string Comment { get; set; } public string ConditionName { get; set; } public int? RentalAgreementId { get; set; } public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } } diff --git a/Server/HetsData/Entities/HetRentalAgreementHist.cs b/Server/HetsData/Entities/HetRentalAgreementHist.cs index fbb9abd12..2b2c98186 100644 --- a/Server/HetsData/Entities/HetRentalAgreementHist.cs +++ b/Server/HetsData/Entities/HetRentalAgreementHist.cs @@ -9,30 +9,82 @@ public partial class HetRentalAgreementHist { public int RentalAgreementHistId { get; set; } public int RentalAgreementId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime _effectiveDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EffectiveDate { + get => DateTime.SpecifyKind(_effectiveDate, DateTimeKind.Utc); + set => _effectiveDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string Number { get; set; } public int? EstimateHours { get; set; } - public DateTime? EstimateStartWork { get; set; } + + private DateTime? _estimateStartWork; + public DateTime? EstimateStartWork { + get => _estimateStartWork is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _estimateStartWork = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string Note { get; set; } public float? EquipmentRate { get; set; } public string RateComment { get; set; } public int RatePeriodTypeId { get; set; } - public DateTime? DatedOn { get; set; } + + private DateTime? _datedOn; + public DateTime? DatedOn { + get => _datedOn is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _datedOn = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int RentalAgreementStatusTypeId { get; set; } public int? EquipmentId { get; set; } public int? ProjectId { get; set; } public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } public string AgreementCity { get; set; } diff --git a/Server/HetsData/Entities/HetRentalAgreementRate.cs b/Server/HetsData/Entities/HetRentalAgreementRate.cs index 4d842e00e..6aa7e6edb 100644 --- a/Server/HetsData/Entities/HetRentalAgreementRate.cs +++ b/Server/HetsData/Entities/HetRentalAgreementRate.cs @@ -23,14 +23,37 @@ public HetRentalAgreementRate() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } public bool? Set { get; set; } diff --git a/Server/HetsData/Entities/HetRentalAgreementRateHist.cs b/Server/HetsData/Entities/HetRentalAgreementRateHist.cs index 479bc8a43..7f9aa2939 100644 --- a/Server/HetsData/Entities/HetRentalAgreementRateHist.cs +++ b/Server/HetsData/Entities/HetRentalAgreementRateHist.cs @@ -9,8 +9,21 @@ public partial class HetRentalAgreementRateHist { public int RentalAgreementRateHistId { get; set; } public int RentalAgreementRateId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime _effectiveDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EffectiveDate { + get => DateTime.SpecifyKind(_effectiveDate, DateTimeKind.Utc); + set => _effectiveDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string Comment { get; set; } public string ComponentName { get; set; } public float? Rate { get; set; } @@ -21,14 +34,37 @@ public partial class HetRentalAgreementRateHist public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } public bool? Set { get; set; } diff --git a/Server/HetsData/Entities/HetRentalAgreementStatusType.cs b/Server/HetsData/Entities/HetRentalAgreementStatusType.cs index 5436a1e8b..035884eec 100644 --- a/Server/HetsData/Entities/HetRentalAgreementStatusType.cs +++ b/Server/HetsData/Entities/HetRentalAgreementStatusType.cs @@ -21,14 +21,37 @@ public HetRentalAgreementStatusType() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetRentalRequest.cs b/Server/HetsData/Entities/HetRentalRequest.cs index 9445be27d..39a2c110f 100644 --- a/Server/HetsData/Entities/HetRentalRequest.cs +++ b/Server/HetsData/Entities/HetRentalRequest.cs @@ -20,8 +20,23 @@ public HetRentalRequest() public int RentalRequestId { get; set; } public int EquipmentCount { get; set; } - public DateTime? ExpectedStartDate { get; set; } - public DateTime? ExpectedEndDate { get; set; } + + private DateTime? _expectedStartDate; + public DateTime? ExpectedStartDate { + get => _expectedStartDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _expectedStartDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _expectedEndDate; + public DateTime? ExpectedEndDate { + get => _expectedEndDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _expectedEndDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? ExpectedHours { get; set; } public int? FirstOnRotationListId { get; set; } public int RentalRequestStatusTypeId { get; set; } @@ -31,14 +46,37 @@ public HetRentalRequest() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } public int FiscalYear { get; set; } diff --git a/Server/HetsData/Entities/HetRentalRequestAttachment.cs b/Server/HetsData/Entities/HetRentalRequestAttachment.cs index 6df67a9cb..309d0de4a 100644 --- a/Server/HetsData/Entities/HetRentalRequestAttachment.cs +++ b/Server/HetsData/Entities/HetRentalRequestAttachment.cs @@ -13,14 +13,37 @@ public partial class HetRentalRequestAttachment public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetRentalRequestRotationList.cs b/Server/HetsData/Entities/HetRentalRequestRotationList.cs index 56c331b20..636294768 100644 --- a/Server/HetsData/Entities/HetRentalRequestRotationList.cs +++ b/Server/HetsData/Entities/HetRentalRequestRotationList.cs @@ -14,12 +14,28 @@ public HetRentalRequestRotationList() public int RentalRequestRotationListId { get; set; } public int RotationListSortOrder { get; set; } - public DateTime? AskedDateTime { get; set; } + + private DateTime? _askedDateTime; + public DateTime? AskedDateTime { + get => _askedDateTime is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _askedDateTime = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public bool? WasAsked { get; set; } public string OfferResponse { get; set; } public string OfferResponseNote { get; set; } public string OfferRefusalReason { get; set; } - public DateTime? OfferResponseDatetime { get; set; } + + private DateTime? _offerResponseDatetime; + public DateTime? OfferResponseDatetime { + get => _offerResponseDatetime is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _offerResponseDatetime = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public bool? IsForceHire { get; set; } public string Note { get; set; } public int? EquipmentId { get; set; } @@ -28,14 +44,37 @@ public HetRentalRequestRotationList() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } public int? BlockNumber { get; set; } diff --git a/Server/HetsData/Entities/HetRentalRequestRotationListHist.cs b/Server/HetsData/Entities/HetRentalRequestRotationListHist.cs index 21431a307..411f9e142 100644 --- a/Server/HetsData/Entities/HetRentalRequestRotationListHist.cs +++ b/Server/HetsData/Entities/HetRentalRequestRotationListHist.cs @@ -9,15 +9,46 @@ public partial class HetRentalRequestRotationListHist { public int RentalRequestRotationListHistId { get; set; } public int RentalRequestRotationListId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? EndDate { get; set; } + + private DateTime? _effectiveDate; + public DateTime? EffectiveDate { + get => _effectiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _effectiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int RotationListSortOrder { get; set; } - public DateTime? AskedDateTime { get; set; } + + private DateTime? _askedDateTime; + public DateTime? AskedDateTime { + get => _askedDateTime is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _askedDateTime = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public bool? WasAsked { get; set; } public string OfferResponse { get; set; } public string OfferResponseNote { get; set; } public string OfferRefusalReason { get; set; } - public DateTime? OfferResponseDatetime { get; set; } + + private DateTime? _offerResponseDatetime; + public DateTime? OfferResponseDatetime { + get => _offerResponseDatetime is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _offerResponseDatetime = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public bool? IsForceHire { get; set; } public string Note { get; set; } public int? EquipmentId { get; set; } @@ -26,14 +57,37 @@ public partial class HetRentalRequestRotationListHist public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } public int? BlockNumber { get; set; } diff --git a/Server/HetsData/Entities/HetRentalRequestSeniorityList.cs b/Server/HetsData/Entities/HetRentalRequestSeniorityList.cs index f5d5e87d5..f1b4a3a87 100644 --- a/Server/HetsData/Entities/HetRentalRequestSeniorityList.cs +++ b/Server/HetsData/Entities/HetRentalRequestSeniorityList.cs @@ -15,14 +15,35 @@ public partial class HetRentalRequestSeniorityList public string Make { get; set; } public string Model { get; set; } public string Year { get; set; } - public DateTime ReceivedDate { get; set; } + + private DateTime _receivedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime ReceivedDate { + get => DateTime.SpecifyKind(_receivedDate, DateTimeKind.Utc); + set => _receivedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public float? YearsOfService { get; set; } public string LicencePlate { get; set; } public string SerialNumber { get; set; } public string Size { get; set; } public float? Seniority { get; set; } - public DateTime? SeniorityEffectiveDate { get; set; } - public DateTime? ToDate { get; set; } + + private DateTime? _seniorityEffectiveDate; + public DateTime? SeniorityEffectiveDate { + get => _seniorityEffectiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _seniorityEffectiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _toDate; + public DateTime? ToDate { + get => _toDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _toDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? NumberInBlock { get; set; } public int? BlockNumber { get; set; } public float? ServiceHoursLastYear { get; set; } @@ -30,13 +51,37 @@ public partial class HetRentalRequestSeniorityList public float? ServiceHoursTwoYearsAgo { get; set; } public bool? IsSeniorityOverridden { get; set; } public string SeniorityOverrideReason { get; set; } - public DateTime? ApprovedDate { get; set; } + + private DateTime? _approvedDate; + public DateTime? ApprovedDate { + get => _approvedDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _approvedDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int EquipmentStatusTypeId { get; set; } public string StatusComment { get; set; } - public DateTime? ArchiveDate { get; set; } + + private DateTime? _archiveDate; + public DateTime? ArchiveDate { + get => _archiveDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _archiveDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string ArchiveCode { get; set; } public string ArchiveReason { get; set; } - public DateTime LastVerifiedDate { get; set; } + + private DateTime? _lastVerifiedDate; + public DateTime? LastVerifiedDate { + get => _lastVerifiedDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _lastVerifiedDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string InformationUpdateNeededReason { get; set; } public bool? IsInformationUpdateNeeded { get; set; } public int? DistrictEquipmentTypeId { get; set; } @@ -54,14 +99,37 @@ public partial class HetRentalRequestSeniorityList public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimeStamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimeStamp, DateTimeKind.Utc); + set => _appCreateTimeStamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetRentalRequestStatusType.cs b/Server/HetsData/Entities/HetRentalRequestStatusType.cs index c5a8de0db..6b34e9880 100644 --- a/Server/HetsData/Entities/HetRentalRequestStatusType.cs +++ b/Server/HetsData/Entities/HetRentalRequestStatusType.cs @@ -21,14 +21,37 @@ public HetRentalRequestStatusType() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetRole.cs b/Server/HetsData/Entities/HetRole.cs index c74a80fd0..e0f4fb43d 100644 --- a/Server/HetsData/Entities/HetRole.cs +++ b/Server/HetsData/Entities/HetRole.cs @@ -20,14 +20,37 @@ public HetRole() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetRolePermission.cs b/Server/HetsData/Entities/HetRolePermission.cs index a3d4b033e..f4c68b03c 100644 --- a/Server/HetsData/Entities/HetRolePermission.cs +++ b/Server/HetsData/Entities/HetRolePermission.cs @@ -13,14 +13,37 @@ public partial class HetRolePermission public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetSeniorityAudit.cs b/Server/HetsData/Entities/HetSeniorityAudit.cs index 22820c924..6f05e870d 100644 --- a/Server/HetsData/Entities/HetSeniorityAudit.cs +++ b/Server/HetsData/Entities/HetSeniorityAudit.cs @@ -8,8 +8,19 @@ namespace HetsData.Entities public partial class HetSeniorityAudit { public int SeniorityAuditId { get; set; } - public DateTime StartDate { get; set; } - public DateTime EndDate { get; set; } + + private DateTime _startDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime StartDate { + get => DateTime.SpecifyKind(_startDate, DateTimeKind.Utc); + set => _startDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _endDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EndDate { + get => DateTime.SpecifyKind(_endDate, DateTimeKind.Utc); + set => _endDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string OwnerOrganizationName { get; set; } public float? Seniority { get; set; } public int? BlockNumber { get; set; } @@ -24,14 +35,37 @@ public partial class HetSeniorityAudit public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetServiceArea.cs b/Server/HetsData/Entities/HetServiceArea.cs index c4772bf52..1ac4c9222 100644 --- a/Server/HetsData/Entities/HetServiceArea.cs +++ b/Server/HetsData/Entities/HetServiceArea.cs @@ -16,8 +16,21 @@ public HetServiceArea() public string Name { get; set; } public int? AreaNumber { get; set; } public int MinistryServiceAreaId { get; set; } - public DateTime FiscalStartDate { get; set; } - public DateTime? FiscalEndDate { get; set; } + + private DateTime _fiscalStartDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime FiscalStartDate { + get => DateTime.SpecifyKind(_fiscalStartDate, DateTimeKind.Utc); + set => _fiscalStartDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _fiscalEndDate; + public DateTime? FiscalEndDate { + get => _fiscalEndDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _fiscalEndDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string Address { get; set; } public string Phone { get; set; } public string Fax { get; set; } @@ -26,14 +39,37 @@ public HetServiceArea() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetTimePeriodType.cs b/Server/HetsData/Entities/HetTimePeriodType.cs index 53145ec99..ac88a71a9 100644 --- a/Server/HetsData/Entities/HetTimePeriodType.cs +++ b/Server/HetsData/Entities/HetTimePeriodType.cs @@ -21,14 +21,37 @@ public HetTimePeriodType() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetTimeRecord.cs b/Server/HetsData/Entities/HetTimeRecord.cs index 154d7f926..cdcbc3b1c 100644 --- a/Server/HetsData/Entities/HetTimeRecord.cs +++ b/Server/HetsData/Entities/HetTimeRecord.cs @@ -8,8 +8,21 @@ namespace HetsData.Entities public partial class HetTimeRecord { public int TimeRecordId { get; set; } - public DateTime? EnteredDate { get; set; } - public DateTime WorkedDate { get; set; } + + private DateTime? _enteredDate; + public DateTime? EnteredDate { + get => _enteredDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _enteredDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime _workedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime WorkedDate { + get => DateTime.SpecifyKind(_workedDate, DateTimeKind.Utc); + set => _workedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public int TimePeriodTypeId { get; set; } public float? Hours { get; set; } public int? RentalAgreementRateId { get; set; } @@ -17,14 +30,37 @@ public partial class HetTimeRecord public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetTimeRecordHist.cs b/Server/HetsData/Entities/HetTimeRecordHist.cs index 5ee1e80f9..a856a31da 100644 --- a/Server/HetsData/Entities/HetTimeRecordHist.cs +++ b/Server/HetsData/Entities/HetTimeRecordHist.cs @@ -9,10 +9,35 @@ public partial class HetTimeRecordHist { public int TimeRecordHistId { get; set; } public int TimeRecordId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? EndDate { get; set; } - public DateTime? EnteredDate { get; set; } - public DateTime WorkedDate { get; set; } + + private DateTime _effectiveDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EffectiveDate { + get => DateTime.SpecifyKind(_effectiveDate, DateTimeKind.Utc); + set => _effectiveDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _endDate; + public DateTime? EndDate { + get => _endDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _endDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _enteredDate; + public DateTime? EnteredDate { + get => _enteredDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _enteredDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime _workedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime WorkedDate { + get => DateTime.SpecifyKind(_workedDate, DateTimeKind.Utc); + set => _workedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public int TimePeriodTypeId { get; set; } public float? Hours { get; set; } public int? RentalAgreementRateId { get; set; } @@ -20,14 +45,37 @@ public partial class HetTimeRecordHist public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } } diff --git a/Server/HetsData/Entities/HetUser.cs b/Server/HetsData/Entities/HetUser.cs index 63359edbc..b98881b8c 100644 --- a/Server/HetsData/Entities/HetUser.cs +++ b/Server/HetsData/Entities/HetUser.cs @@ -28,14 +28,37 @@ public HetUser() public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetUserDistrict.cs b/Server/HetsData/Entities/HetUserDistrict.cs index 77d468001..fbb5f819d 100644 --- a/Server/HetsData/Entities/HetUserDistrict.cs +++ b/Server/HetsData/Entities/HetUserDistrict.cs @@ -14,14 +14,37 @@ public partial class HetUserDistrict public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetUserFavourite.cs b/Server/HetsData/Entities/HetUserFavourite.cs index f777ec32b..348a0271b 100644 --- a/Server/HetsData/Entities/HetUserFavourite.cs +++ b/Server/HetsData/Entities/HetUserFavourite.cs @@ -17,14 +17,37 @@ public partial class HetUserFavourite public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Entities/HetUserRole.cs b/Server/HetsData/Entities/HetUserRole.cs index a8fc29d60..287ea7699 100644 --- a/Server/HetsData/Entities/HetUserRole.cs +++ b/Server/HetsData/Entities/HetUserRole.cs @@ -8,21 +8,57 @@ namespace HetsData.Entities public partial class HetUserRole { public int UserRoleId { get; set; } - public DateTime EffectiveDate { get; set; } - public DateTime? ExpiryDate { get; set; } + + private DateTime _effectiveDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime EffectiveDate { + get => DateTime.SpecifyKind(_effectiveDate, DateTimeKind.Utc); + set => _effectiveDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _expiryDate; + public DateTime? ExpiryDate { + get => _expiryDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _expiryDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? UserId { get; set; } public int? RoleId { get; set; } public string AppCreateUserDirectory { get; set; } public string AppCreateUserGuid { get; set; } public string AppCreateUserid { get; set; } - public DateTime AppCreateTimestamp { get; set; } + + private DateTime _appCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppCreateTimestamp { + get => DateTime.SpecifyKind(_appCreateTimestamp, DateTimeKind.Utc); + set => _appCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string AppLastUpdateUserDirectory { get; set; } public string AppLastUpdateUserGuid { get; set; } public string AppLastUpdateUserid { get; set; } - public DateTime AppLastUpdateTimestamp { get; set; } + + private DateTime _appLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime AppLastUpdateTimestamp { + get => DateTime.SpecifyKind(_appLastUpdateTimestamp, DateTimeKind.Utc); + set => _appLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbCreateUserId { get; set; } - public DateTime DbCreateTimestamp { get; set; } - public DateTime DbLastUpdateTimestamp { get; set; } + + private DateTime _dbCreateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbCreateTimestamp { + get => DateTime.SpecifyKind(_dbCreateTimestamp, DateTimeKind.Utc); + set => _dbCreateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime _dbLastUpdateTimestamp = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime DbLastUpdateTimestamp { + get => DateTime.SpecifyKind(_dbLastUpdateTimestamp, DateTimeKind.Utc); + set => _dbLastUpdateTimestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + public string DbLastUpdateUserId { get; set; } public int ConcurrencyControlNumber { get; set; } diff --git a/Server/HetsData/Extension/HetAttachmentExtension.cs b/Server/HetsData/Extension/HetAttachmentExtension.cs index 77f311e66..7b8ecf2cb 100644 --- a/Server/HetsData/Extension/HetAttachmentExtension.cs +++ b/Server/HetsData/Extension/HetAttachmentExtension.cs @@ -26,7 +26,7 @@ public DateTime? LastUpdateTimestamp { if (value != null) { - AppLastUpdateTimestamp = (DateTime)value; + AppLastUpdateTimestamp = DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc); } } } diff --git a/Server/HetsData/Extension/HetBusinessUserExtension.cs b/Server/HetsData/Extension/HetBusinessUserExtension.cs index efc56d79b..188970c46 100644 --- a/Server/HetsData/Extension/HetBusinessUserExtension.cs +++ b/Server/HetsData/Extension/HetBusinessUserExtension.cs @@ -34,7 +34,7 @@ public ClaimsIdentity ToClaimsIdentity() private List GetClaims() { - List claims = new List + List claims = new() { new Claim(ClaimTypes.Name, BceidUserId), new Claim(ClaimTypes.Actor, "BusinessUser") @@ -84,7 +84,7 @@ private List GetActivePermissions() private List GetActiveRoles() { - List roles = new List(); + List roles = new(); if (HetBusinessUserRoles == null) { diff --git a/Server/HetsData/Extension/HetEquipmentExtension.cs b/Server/HetsData/Extension/HetEquipmentExtension.cs index e5a917a31..7c613d004 100644 --- a/Server/HetsData/Extension/HetEquipmentExtension.cs +++ b/Server/HetsData/Extension/HetEquipmentExtension.cs @@ -1,4 +1,5 @@ -using System; +using HetsCommon; +using System; using System.ComponentModel.DataAnnotations.Schema; namespace HetsData.Entities @@ -143,15 +144,17 @@ public void CalculateYearsOfService(DateTime now) if (now.Month == 1 || now.Month == 2 || now.Month == 3) { - fiscalEnd = new DateTime(now.Year, 3, 31); + fiscalEnd = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.Year, 3, 31, 0, 0, 0, DateTimeKind.Unspecified)); } else { - fiscalEnd = new DateTime(now.AddYears(1).Year, 3, 31); + fiscalEnd = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.AddYears(1).Year, 3, 31, 0, 0, 0, DateTimeKind.Unspecified)); } // calculate and set the To Date - YearsOfService = YearsOfService + 1; + YearsOfService++; ToDate = fiscalEnd; } diff --git a/Server/HetsData/Extension/HetProjectExtension.cs b/Server/HetsData/Extension/HetProjectExtension.cs index 1f655e33a..ec0ad0c6c 100644 --- a/Server/HetsData/Extension/HetProjectExtension.cs +++ b/Server/HetsData/Extension/HetProjectExtension.cs @@ -21,6 +21,12 @@ public partial class HetProject public string Status { get; set; } [NotMapped] - public DateTime FiscalYearStartDate { get; set; } + private DateTime _fiscalYearStartDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + + [NotMapped] + public DateTime FiscalYearStartDate { + get => DateTime.SpecifyKind(_fiscalYearStartDate, DateTimeKind.Utc); + set => _fiscalYearStartDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } } } diff --git a/Server/HetsData/Extension/HetUserExtension.cs b/Server/HetsData/Extension/HetUserExtension.cs index fd363c3db..53fd909b3 100644 --- a/Server/HetsData/Extension/HetUserExtension.cs +++ b/Server/HetsData/Extension/HetUserExtension.cs @@ -34,7 +34,7 @@ public ClaimsIdentity ToClaimsIdentity() private List GetClaims() { - List claims = new List { new Claim(ClaimTypes.Name, SmUserId) }; + List claims = new() { new Claim(ClaimTypes.Name, SmUserId) }; if (!string.IsNullOrEmpty(Surname)) claims.Add(new Claim(ClaimTypes.Surname, Surname)); @@ -83,7 +83,7 @@ private List GetActivePermissions() private List GetActiveRoles() { - List roles = new List(); + List roles = new(); if (HetUserRoles == null) { diff --git a/Server/HetsData/Hangfire/AnnualRollover.cs b/Server/HetsData/Hangfire/AnnualRollover.cs index 6815c5413..8915ba2ac 100644 --- a/Server/HetsData/Hangfire/AnnualRollover.cs +++ b/Server/HetsData/Hangfire/AnnualRollover.cs @@ -88,7 +88,7 @@ public void AnnualRolloverJob(int districtId, string seniorityScoringRules) var rolloverYear = FiscalHelper.GetCurrentFiscalStartYear(); // get processing rules - SeniorityScoringRules scoringRules = new SeniorityScoringRules(seniorityScoringRules, (errMessage, ex) => { + SeniorityScoringRules scoringRules = new(seniorityScoringRules, (errMessage, ex) => { _logger.LogError(errMessage); _logger.LogError(ex.ToString()); }); @@ -129,11 +129,6 @@ public void AnnualRolloverJob(int districtId, string seniorityScoringRules) return; } - //// determine the "Rollover Date" (required for testing) - //DateTime rolloverDate = new DateTime(rolloverYear, DateTime.UtcNow.Month, DateTime.UtcNow.Day); - //status.CurrentFiscalYear = rolloverYear; - //status.NextFiscalYear = rolloverYear + 1; - // get all district equipment types List equipmentTypes = _dbContextMain.HetDistrictEquipmentTypes .Include(x => x.EquipmentType) @@ -266,12 +261,12 @@ public void AnnualRolloverJob(int districtId, string seniorityScoringRules) } catch (Exception e) { - _logger.LogError($"AnnualRolloverJob exception: {e.ToString()}"); + _logger.LogError("AnnualRolloverJob exception: {e}", e); throw; } } - private void UpdateStatusComplete(HetDistrictStatus status, int localAreaCompleteCount, int equipmentCompleteCount) + private static void UpdateStatusComplete(HetDistrictStatus status, int localAreaCompleteCount, int equipmentCompleteCount) { var rolloverYear = FiscalHelper.GetCurrentFiscalStartYear(); diff --git a/Server/HetsData/Helpers/EquipmentHelper.cs b/Server/HetsData/Helpers/EquipmentHelper.cs index 7460059e5..5ea279d20 100644 --- a/Server/HetsData/Helpers/EquipmentHelper.cs +++ b/Server/HetsData/Helpers/EquipmentHelper.cs @@ -9,6 +9,7 @@ using HetsData.Entities; using HetsApi.Helpers; using HetsData.Dtos; +using HetsCommon; namespace HetsData.Helpers { @@ -72,7 +73,15 @@ public class EquipmentLiteDto public string EquipmentPrefix { get; set; } public int EquipmentNumber { get; set; } public int AttachmentCount { get; set; } - public DateTime? LastVerifiedDate { get; set; } + + private DateTime? _lastVerifiedDate; + public DateTime? LastVerifiedDate { + get => _lastVerifiedDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _lastVerifiedDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int SenioritySortOrder { get; set; } public string ProjectName { get; set; } public int ProjectId { get; set; } @@ -222,7 +231,7 @@ public static EquipmentLiteDto ToLiteModel(HetEquipment equipment, SeniorityScor 0; equipmentLite.AttachmentCount = CalculateAttachmentCount(equipment.HetEquipmentAttachments.ToList()); - equipmentLite.LastVerifiedDate = equipment.LastVerifiedDate; + equipmentLite.LastVerifiedDate = DateUtils.AsUTC(equipment.LastVerifiedDate); equipmentLite.Status = equipment.EquipmentStatusType.EquipmentStatusTypeCode; equipmentLite.LocalArea = equipment.LocalArea.Name; @@ -359,8 +368,11 @@ public static float GetYtdServiceHours(int id, DbAppContext context) fiscalYear = (int)district.NextFiscalYear; // status table uses the start of the year } - DateTime fiscalEnd = new DateTime(fiscalYear, 3, 31); - DateTime fiscalStart = new DateTime(fiscalYear - 1, 4, 1); + DateTime fiscalEnd = DateUtils.ConvertPacificToUtcTime( + new DateTime(fiscalYear, 3, 31, 0, 0, 0, DateTimeKind.Unspecified)); + + DateTime fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(fiscalYear - 1, 4, 1, 0, 0, 0, DateTimeKind.Unspecified)); // ******************************************************************************* // get all the time data for the current fiscal year @@ -607,27 +619,21 @@ public static List GetHistoryRecords(int id, int? offset, int? limit, D .OrderByDescending(y => y.AppLastUpdateTimestamp) .ToList(); - if (offset == null) - { - offset = 0; - } + offset ??= 0; - if (limit == null) - { - limit = data.Count - offset; - } + limit ??= data.Count - offset; - List result = new List(); + List result = new(); for (int i = (int)offset; i < data.Count && i < offset + limit; i++) { - History temp = new History(); + History temp = new(); if (data[i] != null) { temp.HistoryText = data[i].HistoryText; temp.Id = data[i].HistoryId; - temp.LastUpdateTimestamp = data[i].AppLastUpdateTimestamp; + temp.LastUpdateTimestamp = DateUtils.AsUTC(data[i].AppLastUpdateTimestamp); temp.LastUpdateUserid = data[i].AppLastUpdateUserid; temp.AffectedEntityId = data[i].EquipmentId; } diff --git a/Server/HetsData/Helpers/HistoryHelper.cs b/Server/HetsData/Helpers/HistoryHelper.cs index db73bb5ca..7bcd0845c 100644 --- a/Server/HetsData/Helpers/HistoryHelper.cs +++ b/Server/HetsData/Helpers/HistoryHelper.cs @@ -9,7 +9,15 @@ public class History public int? Id { get; set; } public string HistoryText { get; set; } public string LastUpdateUserid { get; set; } - public DateTime? LastUpdateTimestamp { get; set; } + + private DateTime? _lastUpdateTimestamp; + public DateTime? LastUpdateTimestamp { + get => _lastUpdateTimestamp is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _lastUpdateTimestamp = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int? AffectedEntityId { get; set; } } diff --git a/Server/HetsData/Helpers/OwnerHelper.cs b/Server/HetsData/Helpers/OwnerHelper.cs index c42d387e5..d60e9d27e 100644 --- a/Server/HetsData/Helpers/OwnerHelper.cs +++ b/Server/HetsData/Helpers/OwnerHelper.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Configuration; using HetsData.Entities; using HetsData.Dtos; +using HetsCommon; namespace HetsData.Helpers { @@ -47,9 +48,24 @@ public class OwnerWcbCgl public string PrimaryContactNumber { get; set; } public string PrimaryContactCell { get; set; } public string WcbNumber { get; set; } - public DateTime? WcbExpiryDate { get; set; } + + private DateTime? _wcbExpiryDate; + public DateTime? WcbExpiryDate { + get => _wcbExpiryDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _wcbExpiryDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string CglNumber { get; set; } - public DateTime? CglExpiryDate { get; set; } + + private DateTime? _cglExpiryDate; + public DateTime? CglExpiryDate { + get => _cglExpiryDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _cglExpiryDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } } public class OwnerLiteProjects @@ -192,9 +208,13 @@ public static OwnerWcbCgl ToWcbCglModel(HetOwner owner) } ownerLite.WcbNumber = owner.WorkSafeBcpolicyNumber; - ownerLite.WcbExpiryDate = owner.WorkSafeBcexpiryDate; + ownerLite.WcbExpiryDate = + owner.WorkSafeBcexpiryDate is DateTime wcbExpiryDateUtc ? + DateUtils.AsUTC(wcbExpiryDateUtc) : null; ownerLite.CglNumber = owner.CglPolicyNumber; - ownerLite.CglExpiryDate = owner.CglendDate; + ownerLite.CglExpiryDate = + owner.CglendDate is DateTime cglEndDateUtc ? + DateUtils.AsUTC(cglEndDateUtc) : null; } return ownerLite; diff --git a/Server/HetsData/Helpers/ProjectHelper.cs b/Server/HetsData/Helpers/ProjectHelper.cs index bc5cda377..d9a6ade55 100644 --- a/Server/HetsData/Helpers/ProjectHelper.cs +++ b/Server/HetsData/Helpers/ProjectHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using HetsCommon; using HetsData.Dtos; using HetsData.Entities; using Microsoft.EntityFrameworkCore; @@ -64,27 +65,21 @@ public static List GetHistoryRecords(int id, int? offset, int? limit, D .OrderByDescending(y => y.AppLastUpdateTimestamp) .ToList(); - if (offset == null) - { - offset = 0; - } + offset ??= 0; - if (limit == null) - { - limit = data.Count - offset; - } + limit ??= data.Count - offset; - List result = new List(); + List result = new(); for (int i = (int)offset; i < data.Count && i < offset + limit; i++) { - History temp = new History(); + History temp = new(); if (data[i] != null) { temp.HistoryText = data[i].HistoryText; temp.Id = data[i].HistoryId; - temp.LastUpdateTimestamp = data[i].AppLastUpdateTimestamp; + temp.LastUpdateTimestamp = DateUtils.AsUTC(data[i].AppLastUpdateTimestamp); temp.LastUpdateUserid = data[i].AppLastUpdateUserid; temp.AffectedEntityId = data[i].ProjectId; } diff --git a/Server/HetsData/Helpers/RentalAgreementHelper.cs b/Server/HetsData/Helpers/RentalAgreementHelper.cs index 5ee95eaea..9ac8ce521 100644 --- a/Server/HetsData/Helpers/RentalAgreementHelper.cs +++ b/Server/HetsData/Helpers/RentalAgreementHelper.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text.RegularExpressions; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; using HetsData.Entities; using HetsData.Dtos; +using HetsCommon; namespace HetsData.Helpers { @@ -14,7 +13,14 @@ namespace HetsData.Helpers public class RentalAgreementSummaryLite { public int Id { get; set; } - public DateTime? DatedOn { get; set; } + + private DateTime? _datedOn; + public DateTime? DatedOn { + get => _datedOn is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _datedOn = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } } public class RentalAgreementDocViewModel @@ -63,12 +69,13 @@ public static class RentalAgreementHelper /// public static RentalAgreementSummaryLite ToSummaryLiteModel(HetRentalAgreement agreement) { - RentalAgreementSummaryLite agreementSummary = new RentalAgreementSummaryLite(); + RentalAgreementSummaryLite agreementSummary = new(); if (agreement != null) { agreementSummary.Id = agreement.RentalAgreementId; - agreementSummary.DatedOn = agreement.DatedOn; + agreementSummary.DatedOn = + agreement.DatedOn is DateTime datedOnUtc ? DateUtils.AsUTC(datedOnUtc) : null; } return agreementSummary; @@ -103,19 +110,22 @@ public static string GetRentalAgreementNumber(int? localAreaId, DbAppContext con // get fiscal year HetDistrictStatus status = context.HetDistrictStatuses.AsNoTracking() - .First(x => x.DistrictId == districtId); + .First(x => x.DistrictId == districtId); int? fiscalYear = status.CurrentFiscalYear; if (fiscalYear == null) return result; // fiscal year in the status table stores the "start" of the year - DateTime fiscalYearStart = new DateTime((int)fiscalYear, 4, 1); - fiscalYear = fiscalYear + 1; + DateTime fiscalYearStart = DateUtils.ConvertPacificToUtcTime( + new DateTime((int)fiscalYear, 4, 1, 0, 0, 0, DateTimeKind.Unspecified)); + + fiscalYear++; // count the number of rental agreements in the system in this district int currentCount = context.HetRentalAgreements - .Count(x => x.DistrictId == districtId && - x.AppCreateTimestamp >= fiscalYearStart); + .Count(x => + x.DistrictId == districtId + && x.AppCreateTimestamp >= fiscalYearStart); currentCount++; @@ -123,9 +133,11 @@ public static string GetRentalAgreementNumber(int? localAreaId, DbAppContext con // * FY-DD-#### // FY = last 2 digits of the year // DD - District(2 digits - 1 to 11) - result = fiscalYear.ToString().Substring(2, 2) + "-" + - ministryDistrictId + "-" + - currentCount.ToString("D4"); + result = fiscalYear.ToString().Substring(2, 2) + + "-" + + ministryDistrictId + + "-" + + currentCount.ToString("D4"); } return result; @@ -158,15 +170,17 @@ public static string GetRentalAgreementNumber(HetDistrict district, DbAppContext int districtNumber = district.MinistryDistrictId; int districtId = district.DistrictId; - DateTime fiscalYearStart = new DateTime(fiscalYear - 1, 1, 1); + DateTime fiscalYearStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(fiscalYear - 1, 1, 1, 0, 0, 0, DateTimeKind.Unspecified)); // count the number of rental agreements in the system (for this district) HetRentalAgreement agreement = context.HetRentalAgreements.AsNoTracking() .Include(x => x.Project.District) .OrderBy(x => x.RentalAgreementId) - .LastOrDefault(x => x.DistrictId == districtId && - x.AppCreateTimestamp >= fiscalYearStart && - x.Number.Contains("-D")); + .LastOrDefault(x => + x.DistrictId == districtId + && x.AppCreateTimestamp >= fiscalYearStart + && x.Number.Contains("-D")); if (agreement != null) { diff --git a/Server/HetsData/Helpers/RentalRequestHelper.cs b/Server/HetsData/Helpers/RentalRequestHelper.cs index 6e119bf41..99d911992 100644 --- a/Server/HetsData/Helpers/RentalRequestHelper.cs +++ b/Server/HetsData/Helpers/RentalRequestHelper.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text.RegularExpressions; using AutoMapper; +using HetsCommon; using HetsData.Dtos; using HetsData.Entities; using Microsoft.EntityFrameworkCore; @@ -23,8 +24,23 @@ public class RentalRequestLite public ContactDto PrimaryContact { get; set; } public string Status { get; set; } public int? ProjectId { get; set; } - public DateTime? ExpectedStartDate { get; set; } - public DateTime? ExpectedEndDate { get; set; } + + private DateTime? _expectedStartDate; + public DateTime? ExpectedStartDate { + get => _expectedStartDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _expectedStartDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + + private DateTime? _expectedEndDate; + public DateTime? ExpectedEndDate { + get => _expectedEndDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _expectedEndDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public int YesCount { get; set; } } @@ -46,7 +62,15 @@ public class RentalRequestHires public string EquipmentYear { get; set; } public int ProjectId { get; set; } public string ProjectNumber { get; set; } - public DateTime? NoteDate { get; set; } + + private DateTime? _noteDate; + public DateTime? NoteDate { + get => _noteDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _noteDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string NoteType { get; set; } public string Reason { get; set; } public string OfferResponseNote { get; set; } @@ -69,14 +93,13 @@ public static class RentalRequestHelper /// public static RentalRequestHires ToHiresModel(HetRentalRequestRotationList request, HetUser user) { - RentalRequestHires requestLite = new RentalRequestHires(); + RentalRequestHires requestLite = new(); if (request != null) { requestLite.Id = request.RentalRequestRotationListId; requestLite.OwnerId = request.Equipment.OwnerId ?? 0; requestLite.EquipmentId = request.EquipmentId ?? 0; - requestLite.LocalAreaName = request.RentalRequest.LocalArea.Name; requestLite.ServiceAreaId = request.RentalRequest.LocalArea.ServiceArea.ServiceAreaId; @@ -96,8 +119,8 @@ public static RentalRequestHires ToHiresModel(HetRentalRequestRotationList reque // project data requestLite.ProjectId = request.RentalRequest.Project.ProjectId; requestLite.ProjectNumber = request.RentalRequest.Project.ProvincialProjectNumber; - - requestLite.NoteDate = request.OfferResponseDatetime; + requestLite.NoteDate = request.OfferResponseDatetime is DateTime offerResponseDtUtc + ? DateUtils.AsUTC(offerResponseDtUtc) : null; // Note Type - // * Not hired (for recording the response NO for hiring. @@ -197,10 +220,10 @@ public static HetRentalRequest CreateRotationList( // get the number of blocks for this piece of equipment int numberOfBlocks = GetNumberOfBlocks(request, context, configuration, logErrorAction); - numberOfBlocks = numberOfBlocks + 1; + numberOfBlocks++; - int? statusId = StatusHelper.GetStatusId(HetEquipment.StatusApproved, "equipmentStatus", context); - if (statusId == null) throw new ArgumentException("Status Id cannot be null"); + int? statusId = StatusHelper.GetStatusId(HetEquipment.StatusApproved, "equipmentStatus", context) + ?? throw new ArgumentException("Status Id cannot be null"); // get the equipment based on the current seniority list for the area // (and sort the results based on block then @@ -220,7 +243,7 @@ public static HetRentalRequest CreateRotationList( for (int i = 0; i < listSize; i++) { - HetRentalRequestRotationList rentalRequestRotationList = new HetRentalRequestRotationList + HetRentalRequestRotationList rentalRequestRotationList = new() { Equipment = blockEquipment[i], EquipmentId = blockEquipment[i].EquipmentId, @@ -280,18 +303,24 @@ private static void DropHiredEquipment(List hetRen } } - private static HetEquipment LastAskedByBlockInRotationList(int blockNumber, int? districtEquipmentTypeId, - int? localAreaId, DateTime fiscalStart, DbAppContext context, List hetRentalRequestRotationList) + private static HetEquipment LastAskedByBlockInRotationList( + int blockNumber, + int? districtEquipmentTypeId, + int? localAreaId, + DateTime fiscalStart, + DbAppContext context, + List hetRentalRequestRotationList) { if (districtEquipmentTypeId == null || localAreaId == null) return null; // if this is not block 1 - check that we have "asked" anyone in the previous list + DateTime fiscalStartUtc = DateUtils.AsUTC(fiscalStart); var rotationListquery = context.HetRentalRequestRotationLists.AsNoTracking() .Include(x => x.RentalRequest) .Include(x => x.Equipment) .Where(x => x.RentalRequest.DistrictEquipmentTypeId == districtEquipmentTypeId && x.RentalRequest.LocalAreaId == localAreaId && - x.RentalRequest.AppCreateTimestamp >= fiscalStart && + x.RentalRequest.AppCreateTimestamp >= fiscalStartUtc && x.BlockNumber == blockNumber && //use historical block number of the equipment x.WasAsked == true && x.IsForceHire != true) @@ -307,18 +336,24 @@ private static HetEquipment LastAskedByBlockInRotationList(int blockNumber, int? return null; } - private static HetEquipment LastAskedByBlockInSeniorityList(int blockNumber, int? districtEquipmentTypeId, - int? localAreaId, DateTime fiscalStart, DbAppContext context, List hetRentalRequestSeniorityList) + private static HetEquipment LastAskedByBlockInSeniorityList( + int blockNumber, + int? districtEquipmentTypeId, + int? localAreaId, + DateTime fiscalStart, + DbAppContext context, + List hetRentalRequestSeniorityList) { if (districtEquipmentTypeId == null || localAreaId == null) return null; // if this is not block 1 - check that we have "asked" anyone in the previous list + DateTime fiscalStartUtc = DateUtils.AsUTC(fiscalStart); var rotationListquery = context.HetRentalRequestRotationLists.AsNoTracking() .Include(x => x.RentalRequest) .Include(x => x.Equipment) .Where(x => x.RentalRequest.DistrictEquipmentTypeId == districtEquipmentTypeId && x.RentalRequest.LocalAreaId == localAreaId && - x.RentalRequest.AppCreateTimestamp >= fiscalStart && + x.RentalRequest.AppCreateTimestamp >= fiscalStartUtc && x.BlockNumber == blockNumber && //use historical block number of the equipment x.WasAsked == true && x.IsForceHire != true) @@ -350,25 +385,22 @@ private static HetEquipment LastAskedByBlockInSeniorityList(int blockNumber, int /// /// /// - public static HetRentalRequest SetupNewRotationList(HetRentalRequest rentalRequest, int numberOfBlocks, DbAppContext context) + public static HetRentalRequest SetupNewRotationList( + HetRentalRequest rentalRequest, int numberOfBlocks, DbAppContext context) { // remove hired equipment from the list DropHiredEquipment((List)rentalRequest.HetRentalRequestRotationLists, context); - // set working now - if an equipment is dropped, it's working now. - foreach(var equipment in rentalRequest.HetRentalRequestSeniorityLists) - { - if (!rentalRequest.HetRentalRequestRotationLists.Any(x => x.EquipmentId == equipment.EquipmentId)) - { - equipment.WorkingNow = true; - } - } + SetWorkingNow(rentalRequest); // nothing to do! if (rentalRequest.HetRentalRequestRotationLists.Count <= 0) return rentalRequest; // sort our new rotation list - var hetRentalRequestRotationList = rentalRequest.HetRentalRequestRotationLists.OrderBy(x => x.RotationListSortOrder).ToList(); + var hetRentalRequestRotationList = rentalRequest.HetRentalRequestRotationLists + .OrderBy(x => x.RotationListSortOrder) + .ToList(); + rentalRequest.HetRentalRequestRotationLists = hetRentalRequestRotationList; int? disEquipmentTypeId = rentalRequest.DistrictEquipmentTypeId; @@ -385,26 +417,18 @@ public static HetRentalRequest SetupNewRotationList(HetRentalRequest rentalReque HetDistrictStatus districtStatus = context.HetDistrictStatuses.AsNoTracking() .First(x => x.DistrictId == localArea.ServiceArea.DistrictId); - DateTime fiscalStart = districtStatus.RolloverEndDate ?? new DateTime(0001, 01, 01, 00, 00, 00); int fiscalYear = Convert.ToInt32(districtStatus.NextFiscalYear); // status table uses the start of the year rentalRequest.FiscalYear = fiscalYear; - if (fiscalStart == new DateTime(0001, 01, 01, 00, 00, 00)) - { - fiscalStart = new DateTime(fiscalYear - 1, 4, 1); - } - - // get the last rotation list created this fiscal year - bool previousRequestExists = context.HetRentalRequests - .Any(x => x.DistrictEquipmentType.DistrictEquipmentTypeId == disEquipmentTypeId && - x.LocalArea.LocalAreaId == localAreaId && - x.AppCreateTimestamp >= fiscalStart); + DateTime fiscalStart = DateUtils.AsUTC( + districtStatus.RolloverEndDate ?? DateUtils.ConvertPacificToUtcTime( + new DateTime(fiscalYear - 1, 4, 1, 0, 0, 0, DateTimeKind.Unspecified))); // ***************************************************************** // if we don't have a request for the current fiscal, // ** pick the first one in the list and we are done. // ***************************************************************** - if (!previousRequestExists) + if (!PreviousRequestExists(context, disEquipmentTypeId, localAreaId, fiscalStart)) { var firstOnList = hetRentalRequestRotationList[0]; rentalRequest.FirstOnRotationListId = firstOnList.EquipmentId; @@ -429,57 +453,26 @@ public static HetRentalRequest SetupNewRotationList(HetRentalRequest rentalReque startEquipInBlock[blockIndex].position = -1; // get the last asked equipment id for this "block". This method ensures that the returned equipment exists in our list. - var lastEquipmentInRotationList = LastAskedByBlockInRotationList(blockNumber, rentalRequest.DistrictEquipmentTypeId, rentalRequest.LocalAreaId, - fiscalStart, context, hetRentalRequestRotationList); - - var lastEquipmentInSeniorityList = LastAskedByBlockInSeniorityList(blockNumber, rentalRequest.DistrictEquipmentTypeId, rentalRequest.LocalAreaId, - fiscalStart, context, rentalRequest.HetRentalRequestSeniorityLists.ToList()); - - if (lastEquipmentInSeniorityList != null) - { - rentalRequest.HetRentalRequestSeniorityLists - .First(x => x.EquipmentId == lastEquipmentInSeniorityList.EquipmentId) - .LastCalled = true; - } - - // nothing found for this block - start at 0 - if (lastEquipmentInRotationList == null && hetRentalRequestRotationList.Count > 0) - { - for (int i = 0; i < hetRentalRequestRotationList.Count; i++) - { - if (hetRentalRequestRotationList[i].BlockNumber != blockNumber) continue; - - startEquipInBlock[blockIndex].equipment = hetRentalRequestRotationList[i].Equipment; - startEquipInBlock[blockIndex].position = i; - break; - } - } - else - { - //we know the equipment exists in the list - var foundIndex = hetRentalRequestRotationList.FindIndex(x => x.EquipmentId == lastEquipmentInRotationList.EquipmentId); - - //find the next record which has the same block - for (int i = foundIndex + 1; i < hetRentalRequestRotationList.Count; i++) - { - if (hetRentalRequestRotationList[i].BlockNumber != blockNumber) continue; - - startEquipInBlock[blockIndex].equipment = hetRentalRequestRotationList[i].Equipment; - startEquipInBlock[blockIndex].position = i; - break; - } - } - - //if we haven't found a start equip yet, choose the first one in the block. - if (startEquipInBlock[blockIndex].equipment == null) - { - var foundIndex = hetRentalRequestRotationList.FindIndex(x => x.BlockNumber == blockNumber); - if (foundIndex >= 0) - { - startEquipInBlock[blockIndex].equipment = hetRentalRequestRotationList[foundIndex].Equipment; - startEquipInBlock[blockIndex].position = foundIndex; - } - } + var lastEquipmentInRotationList = LastAskedByBlockInRotationList( + blockNumber, + rentalRequest.DistrictEquipmentTypeId, + rentalRequest.LocalAreaId, + fiscalStart, + context, + hetRentalRequestRotationList); + + var lastEquipmentInSeniorityList = LastAskedByBlockInSeniorityList( + blockNumber, + rentalRequest.DistrictEquipmentTypeId, + rentalRequest.LocalAreaId, + fiscalStart, + context, + rentalRequest.HetRentalRequestSeniorityLists.ToList()); + + SetSeniorityListLastCalled(rentalRequest, lastEquipmentInSeniorityList); + + SetNextStartEquipWithSameBlock( + hetRentalRequestRotationList, lastEquipmentInRotationList, startEquipInBlock, blockNumber, blockIndex); } // find the starting equipment and its block number on the list @@ -497,6 +490,93 @@ public static HetRentalRequest SetupNewRotationList(HetRentalRequest rentalReque // ***************************************************************** // Reset the rotation list sort order // ***************************************************************** + ResetRotationListSortOrder( + startEquipInBlock, startBlockIndex, hetRentalRequestRotationList, startBlockNumber, numberOfBlocks); + + return rentalRequest; + } + + private static void SetWorkingNow(HetRentalRequest rentalRequest) + { + // set working now - if an equipment is dropped, it's working now. + foreach (var equipment in rentalRequest.HetRentalRequestSeniorityLists) + { + if (!rentalRequest.HetRentalRequestRotationLists.Any(x => x.EquipmentId == equipment.EquipmentId)) + { + equipment.WorkingNow = true; + } + } + } + + private static bool PreviousRequestExists( + DbAppContext context, int? disEquipmentTypeId, int? localAreaId, DateTime fiscalStart) + { + // get the last rotation list created this fiscal year + DateTime fiscalStartUtc = DateUtils.AsUTC(fiscalStart); + return context.HetRentalRequests + .Any(x => + x.DistrictEquipmentType.DistrictEquipmentTypeId == disEquipmentTypeId + && x.LocalArea.LocalAreaId == localAreaId + && x.AppCreateTimestamp >= fiscalStartUtc); + } + + private static void SetSeniorityListLastCalled( + HetRentalRequest rentalRequest, HetEquipment lastEquipmentInSeniorityList) + { + if (lastEquipmentInSeniorityList != null) + { + rentalRequest.HetRentalRequestSeniorityLists + .First(x => x.EquipmentId == lastEquipmentInSeniorityList.EquipmentId) + .LastCalled = true; + } + } + + private static void SetStartEquipInBlock( + (HetEquipment equipment, int position)[] startEquipInBlock, int blockIndex, HetEquipment equipment, int position) + { + startEquipInBlock[blockIndex].equipment = equipment; + startEquipInBlock[blockIndex].position = position; + } + + private static void SetNextStartEquipWithSameBlock( + List hetRentalRequestRotationList, + HetEquipment lastEquipmentInRotationList, + (HetEquipment equipment, int position)[] startEquipInBlock, + int blockNumber, + int blockIndex) + { + int startIndex = + (lastEquipmentInRotationList == null && hetRentalRequestRotationList.Count > 0) + ? 0 // nothing found for this block - start at 0 + : 1 + hetRentalRequestRotationList + .FindIndex(x => x.EquipmentId == lastEquipmentInRotationList.EquipmentId); // we know the equipment exists in the list + + // find the next record which has the same block + for (int i = startIndex; i < hetRentalRequestRotationList.Count; i++) + { + if (hetRentalRequestRotationList[i].BlockNumber != blockNumber) continue; + + SetStartEquipInBlock( + startEquipInBlock, blockIndex, hetRentalRequestRotationList[i].Equipment, i); + break; + } + + // if we haven't found a start equip yet, choose the first one in the block. + var foundIndex = hetRentalRequestRotationList.FindIndex(x => x.BlockNumber == blockNumber); + if (startEquipInBlock[blockIndex].equipment == null && foundIndex >= 0) + { + SetStartEquipInBlock( + startEquipInBlock, blockIndex, hetRentalRequestRotationList[foundIndex].Equipment, foundIndex); + } + } + + private static void ResetRotationListSortOrder( + (HetEquipment equipment, int position)[] startEquipInBlock, + int startBlockIndex, + List hetRentalRequestRotationList, + int startBlockNumber, + int numberOfBlocks) + { int masterSortOrder = 0; #region starting block @@ -520,6 +600,17 @@ public static HetRentalRequest SetupNewRotationList(HetRentalRequest rentalReque } #endregion + ResetRemainingBlocksSortOrder( + startBlockIndex, numberOfBlocks, masterSortOrder, startEquipInBlock, hetRentalRequestRotationList); + } + + private static void ResetRemainingBlocksSortOrder( + int startBlockIndex, + int numberOfBlocks, + int masterSortOrder, + (HetEquipment equipment, int position)[] startEquipInBlock, + List hetRentalRequestRotationList) + { #region remaining blocks if any for (int blockIndex = startBlockIndex + 1; blockIndex < numberOfBlocks; blockIndex++) { @@ -544,8 +635,6 @@ public static HetRentalRequest SetupNewRotationList(HetRentalRequest rentalReque } } #endregion - - return rentalRequest; } /// @@ -609,27 +698,21 @@ public static List GetHistoryRecords(int id, int? offset, int? limit, D .OrderByDescending(y => y.AppLastUpdateTimestamp) .ToList(); - if (offset == null) - { - offset = 0; - } + offset ??= 0; - if (limit == null) - { - limit = data.Count - offset; - } + limit ??= data.Count - offset; - List result = new List(); + List result = new(); for (int i = (int)offset; i < data.Count && i < offset + limit; i++) { - History temp = new History(); + History temp = new(); if (data[i] != null) { temp.HistoryText = data[i].HistoryText; temp.Id = data[i].HistoryId; - temp.LastUpdateTimestamp = data[i].AppLastUpdateTimestamp; + temp.LastUpdateTimestamp = DateUtils.AsUTC(data[i].AppLastUpdateTimestamp); temp.LastUpdateUserid = data[i].AppLastUpdateUserid; temp.AffectedEntityId = data[i].RentalRequestId; } diff --git a/Server/HetsData/Helpers/SecretKeyHelper.cs b/Server/HetsData/Helpers/SecretKeyHelper.cs index 03d8e3646..22a04619c 100644 --- a/Server/HetsData/Helpers/SecretKeyHelper.cs +++ b/Server/HetsData/Helpers/SecretKeyHelper.cs @@ -11,7 +11,7 @@ public static string RandomString(int maxLength, int id) // seed random number generator decimal temp = (DateTime.Now.Millisecond * 1000 / id) + (id * DateTime.Now.Millisecond); int seed = Convert.ToInt32(Math.Round(temp, 0)); - Random rnd = new Random(seed); + Random rnd = new(seed); // create random string char[] chars = new char[maxLength]; diff --git a/Server/HetsData/Helpers/SeniorityListHelper.cs b/Server/HetsData/Helpers/SeniorityListHelper.cs index 063a74ebe..707bcce3f 100644 --- a/Server/HetsData/Helpers/SeniorityListHelper.cs +++ b/Server/HetsData/Helpers/SeniorityListHelper.cs @@ -127,12 +127,8 @@ public static void CalculateSeniorityList(int localAreaId, int districtEquipment x.DistrictEquipmentTypeId == districtEquipmentTypeId); // get status id - int? eqStatusId = - StatusHelper.GetStatusId(HetEquipment.StatusApproved, "equipmentStatus", context); - if (eqStatusId == null) - { - throw new ArgumentException("Status Code not found"); - } + int? eqStatusId = StatusHelper.GetStatusId(HetEquipment.StatusApproved, "equipmentStatus", context) + ?? throw new ArgumentException("Status Code not found"); // update the seniority score foreach (HetEquipment equipment in data) @@ -207,8 +203,18 @@ public static void AssignBlocks( } //reselect with data that include local changes + //var dataToProcess = dataFromDb + // .Where(x => x.EquipmentStatusType != null && x.EquipmentStatusType.EquipmentStatusTypeCode == HetEquipment.StatusApproved && + // x.LocalAreaId == localAreaId && + // x.DistrictEquipmentTypeId == districtEquipmentTypeId) + // .OrderByDescending(x => x.Seniority) + // .ThenBy(x => x.ReceivedDate) + // .ThenBy(x => x.EquipmentCode) + // .ToList(); + + // TH-112626: check if the equipment is archived or approved when the user wants to to bring back the equipment from archived to approved var dataToProcess = dataFromDb - .Where(x => x.EquipmentStatusType != null && x.EquipmentStatusType.EquipmentStatusTypeCode == HetEquipment.StatusApproved && + .Where(x => x.EquipmentStatusType != null && (x.EquipmentStatusType.EquipmentStatusTypeCode == HetEquipment.StatusApproved || x.EquipmentStatusType.EquipmentStatusTypeCode == HetEquipment.StatusArchived) && x.LocalAreaId == localAreaId && x.DistrictEquipmentTypeId == districtEquipmentTypeId) .OrderByDescending(x => x.Seniority) diff --git a/Server/HetsData/Helpers/TimeRecordHelper.cs b/Server/HetsData/Helpers/TimeRecordHelper.cs index 17db576dd..e5ad003c2 100644 --- a/Server/HetsData/Helpers/TimeRecordHelper.cs +++ b/Server/HetsData/Helpers/TimeRecordHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using HetsCommon; using HetsData.Dtos; using HetsData.Entities; @@ -22,8 +23,21 @@ public class TimeRecordSearchLite { public int Id { get; set; } public float? Hours { get; set; } - public DateTime WorkedDate { get; set; } - public DateTime? EnteredDate { get; set; } + + private DateTime _workedDate = new(0001, 01, 01, 00, 00, 00, DateTimeKind.Utc); + public DateTime WorkedDate { + get => DateTime.SpecifyKind(_workedDate, DateTimeKind.Utc); + set => _workedDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + + private DateTime? _enteredDate; + public DateTime? EnteredDate { + get => _enteredDate is DateTime dt ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + set => _enteredDate = (value.HasValue && value.Value is DateTime dt) ? + DateTime.SpecifyKind(dt, DateTimeKind.Utc) : null; + } + public string LocalAreaName { get; set; } public int LocalAreaId { get; set; } public int ServiceAreaId { get; set; } @@ -55,14 +69,15 @@ public static class TimeRecordHelper /// public static TimeRecordSearchLite ToLiteModel(HetTimeRecord timeRecord) { - TimeRecordSearchLite timeLite = new TimeRecordSearchLite(); + TimeRecordSearchLite timeLite = new(); if (timeRecord != null) { timeLite.Id = timeRecord.TimeRecordId; timeLite.Hours = timeRecord.Hours; - timeLite.WorkedDate = timeRecord.WorkedDate; - timeLite.EnteredDate = timeRecord.EnteredDate; + timeLite.WorkedDate = DateUtils.AsUTC(timeRecord.WorkedDate); + timeLite.EnteredDate = timeRecord.EnteredDate is DateTime enteredDateUtc ? + DateUtils.AsUTC(enteredDateUtc) : null; timeLite.RentalAgreementId = timeRecord.RentalAgreement.RentalAgreementId; timeLite.LocalAreaId = timeRecord.RentalAgreement.Equipment.LocalArea.LocalAreaId; timeLite.LocalAreaName = timeRecord.RentalAgreement.Equipment.LocalArea.Name; diff --git a/Server/HetsData/HetsData.csproj b/Server/HetsData/HetsData.csproj index 65c921f95..53ae3806b 100644 --- a/Server/HetsData/HetsData.csproj +++ b/Server/HetsData/HetsData.csproj @@ -1,7 +1,7 @@ - net5.0 + net7.0 Common data code for the HETS application Copyright© 2017, Province of British Columbia Hets Data @@ -11,11 +11,11 @@ - + - - - + + + diff --git a/Server/HetsData/Repositories/OwnerRepository.cs b/Server/HetsData/Repositories/OwnerRepository.cs index a2a108925..d7f185be4 100644 --- a/Server/HetsData/Repositories/OwnerRepository.cs +++ b/Server/HetsData/Repositories/OwnerRepository.cs @@ -11,6 +11,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using HetsCommon; namespace HetsData.Repositories { @@ -19,7 +20,8 @@ public interface IOwnerRepository OwnerDto GetRecord(int id); bool RentalRequestStatus(int id); List GetHistoryRecords(int id, int? offset, int? limit); - OwnerVerificationReportModel GetOwnerVerificationLetterData(int?[] localAreas, int?[] owners, int? equipmentStatusId, int? ownerStatusId, int? districtId); + OwnerVerificationReportModel GetOwnerVerificationLetterData( + int?[] localAreas, int?[] owners, int? equipmentStatusId, int? ownerStatusId, int? districtId); } public class OwnerRepository : IOwnerRepository @@ -47,11 +49,8 @@ public OwnerRepository(DbAppContext dbContext, IMapper mapper, IConfiguration co public OwnerDto GetRecord(int id) { // get equipment status types - int? statusIdArchived = StatusHelper.GetStatusId(HetEquipment.StatusArchived, "equipmentStatus", _dbContext); - if (statusIdArchived == null) - { - throw new ArgumentException("Status Code not found"); - } + int? statusIdArchived = StatusHelper.GetStatusId(HetEquipment.StatusArchived, "equipmentStatus", _dbContext) + ?? throw new ArgumentException("Status Code not found"); // get owner record HetOwner owner = _dbContext.HetOwners.AsNoTracking() @@ -107,18 +106,12 @@ public OwnerDto GetRecord(int id) public bool RentalRequestStatus(int id) { // get equipment status types - int? statusIdActive = StatusHelper.GetStatusId(HetEquipment.StatusApproved, "equipmentStatus", _dbContext); - if (statusIdActive == null) - { - throw new ArgumentException("Status Code not found"); - } + int? statusIdActive = StatusHelper.GetStatusId(HetEquipment.StatusApproved, "equipmentStatus", _dbContext) + ?? throw new ArgumentException("Status Code not found"); // get rental request status type - int? statusIdInProgress = StatusHelper.GetStatusId(HetRentalRequest.StatusInProgress, "rentalRequestStatus", _dbContext); - if (statusIdInProgress == null) - { - throw new ArgumentException("Status Code not found"); - } + int? statusIdInProgress = StatusHelper.GetStatusId(HetRentalRequest.StatusInProgress, "rentalRequestStatus", _dbContext) + ?? throw new ArgumentException("Status Code not found"); return _dbContext.HetRentalRequestRotationLists.AsNoTracking() .Include(x => x.RentalRequest) @@ -126,7 +119,6 @@ public bool RentalRequestStatus(int id) .Any(x => x.Equipment.OwnerId == id && x.Equipment.EquipmentStatusTypeId == statusIdActive && x.RentalRequest.RentalRequestStatusTypeId == statusIdInProgress); - } @@ -140,27 +132,21 @@ public List GetHistoryRecords(int id, int? offset, int? limit) .OrderByDescending(y => y.AppLastUpdateTimestamp) .ToList(); - if (offset == null) - { - offset = 0; - } + offset ??= 0; - if (limit == null) - { - limit = data.Count - offset; - } + limit ??= data.Count - offset; - List result = new List(); + List result = new(); for (int i = (int)offset; i < data.Count && i < offset + limit; i++) { - History temp = new History(); + History temp = new(); if (data[i] != null) { temp.HistoryText = data[i].HistoryText; temp.Id = data[i].HistoryId; - temp.LastUpdateTimestamp = data[i].AppLastUpdateTimestamp; + temp.LastUpdateTimestamp = DateUtils.AsUTC(data[i].AppLastUpdateTimestamp); temp.LastUpdateUserid = data[i].AppLastUpdateUserid; temp.AffectedEntityId = data[i].OwnerId; } @@ -265,7 +251,7 @@ public OwnerVerificationReportModel GetOwnerVerificationLetterData( owner.LocalAreaName = model.LocalAreaName; // classification - owner.Classification = $"23010-23/{model.MinistryDistrictId.ToString()}/{owner.OwnerCode}"; + owner.Classification = $"23010-23/{model.MinistryDistrictId}/{owner.OwnerCode}"; if (!string.IsNullOrEmpty(owner.SharedKey)) { @@ -306,7 +292,7 @@ public OwnerVerificationReportModel GetOwnerVerificationLetterData( } catch (Exception e) { - _logger.LogError($"GetOwnerVerificationLetterData exception: {e.ToString()}"); + _logger.LogError("GetOwnerVerificationLetterData exception: {e}", e); throw; } } diff --git a/Server/HetsData/Repositories/ProjectRepository.cs b/Server/HetsData/Repositories/ProjectRepository.cs index 374b0f09a..22ef57228 100644 --- a/Server/HetsData/Repositories/ProjectRepository.cs +++ b/Server/HetsData/Repositories/ProjectRepository.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore; using System; using System.Linq; +using HetsCommon; namespace HetsData.Repositories { @@ -169,7 +170,9 @@ public ProjectDto GetRecord(int projectId, int? districtId = 0) // fiscal year in the status table stores the "start" of the year if (fiscalYear != null && project != null) { - DateTime fiscalYearStart = new DateTime((int)fiscalYear, 4, 1); + DateTime fiscalYearStart = DateUtils.ConvertPacificToUtcTime( + new DateTime((int)fiscalYear, 4, 1, 0, 0, 0, DateTimeKind.Unspecified)); + project.FiscalYearStartDate = fiscalYearStart; } } diff --git a/Server/HetsData/Repositories/RentalAgreementRepository.cs b/Server/HetsData/Repositories/RentalAgreementRepository.cs index 136cbcf5e..c529463cf 100644 --- a/Server/HetsData/Repositories/RentalAgreementRepository.cs +++ b/Server/HetsData/Repositories/RentalAgreementRepository.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using HetsCommon; namespace HetsData.Repositories { @@ -125,15 +126,18 @@ public TimeRecordLite GetTimeRecords(int id, int? districtId) } // fiscal year in the status table stores the "start" of the year - TimeRecordLite timeRecord = new TimeRecordLite(); + TimeRecordLite timeRecord = new(); if (fiscalYear != null) { - DateTime fiscalYearStart = new DateTime((int)fiscalYear, 4, 1); + DateTime fiscalYearStart = DateUtils.ConvertPacificToUtcTime( + new DateTime((int)fiscalYear, 4, 1, 0, 0, 0, DateTimeKind.Unspecified)); timeRecord.TimeRecords = new List(); - timeRecord.TimeRecords - .AddRange(_mapper.Map>(agreement.HetTimeRecords.Where(x => x.WorkedDate >= fiscalYearStart))); + timeRecord.TimeRecords.AddRange( + _mapper.Map>( + agreement.HetTimeRecords.Where(x => + x.WorkedDate >= fiscalYearStart))); } timeRecord.EquipmentCode = equipmentCode; @@ -176,93 +180,101 @@ public List GetConditions(int id) /// public RentalAgreementDocViewModel GetRentalAgreementReportModel(RentalAgreementDto agreement, string agreementCity) { - RentalAgreementDocViewModel docModel = new RentalAgreementDocViewModel(); - - if (agreement != null) + RentalAgreementDocViewModel docModel = new(); + + if (agreement is null) return docModel; + + docModel.AgreementCity = agreementCity; + docModel.Equipment = agreement.Equipment; + docModel.EquipmentRate = agreement.EquipmentRate; + docModel.EstimateHours = agreement.EstimateHours; + docModel.EstimateStartWork = ConvertDate(agreement.EstimateStartWork); + docModel.Number = agreement.Number; + docModel.Project = agreement.Project; + docModel.RateComment = agreement.RateComment; + docModel.RatePeriod = agreement.RatePeriodType.Description; + docModel.AgreementCity = agreement.AgreementCity; + docModel.DatedOn = DateUtils.AsUTC(agreement.DatedOn ?? DateTime.UtcNow).ToString("MM/dd/yyyy"); + docModel.DoingBusinessAs = agreement.Equipment.Owner.DoingBusinessAs; + docModel.EmailAddress = agreement.Equipment.Owner.PrimaryContact.EmailAddress; + + agreement.Equipment.Owner.Address2 = FormatOwnerAddress(agreement); + + // format the note + if (!string.IsNullOrEmpty(agreement.Note)) { - docModel.AgreementCity = agreementCity; - docModel.Equipment = agreement.Equipment; - docModel.EquipmentRate = agreement.EquipmentRate; - docModel.EstimateHours = agreement.EstimateHours; - docModel.EstimateStartWork = ConvertDate(agreement.EstimateStartWork); - docModel.Number = agreement.Number; - docModel.Project = agreement.Project; - docModel.RateComment = agreement.RateComment; - docModel.RatePeriod = agreement.RatePeriodType.Description; - docModel.AgreementCity = agreement.AgreementCity; - docModel.DatedOn = (agreement.DatedOn ?? DateTime.UtcNow).ToString("MM/dd/yyyy"); - docModel.DoingBusinessAs = agreement.Equipment.Owner.DoingBusinessAs; - docModel.EmailAddress = agreement.Equipment.Owner.PrimaryContact.EmailAddress; - - // format owner address - string tempAddress = agreement.Equipment.Owner.Address2; + string temp = Regex.Replace(agreement.Note, @"\n", "
"); + string[] tempArray = temp.Split("
"); - if (string.IsNullOrEmpty(tempAddress) && !string.IsNullOrEmpty(agreement.Equipment.Owner.City)) - tempAddress = $"{agreement.Equipment.Owner.City}"; + docModel.Note = new List(); - if (!string.IsNullOrEmpty(tempAddress) && !string.IsNullOrEmpty(agreement.Equipment.Owner.City) && agreement.Equipment.Owner.City.Trim() != tempAddress.Trim()) - tempAddress = $"{tempAddress}, {agreement.Equipment.Owner.City}"; + foreach (string row in tempArray) + { + NoteLine line = new() { Line = row }; + docModel.Note.Add(line); + } + } - if (string.IsNullOrEmpty(tempAddress) && !string.IsNullOrEmpty(agreement.Equipment.Owner.Province)) - tempAddress = $"{agreement.Equipment.Owner.Province}"; + // ensure they are ordered the way they were added + docModel.RentalAgreementConditions = agreement.RentalAgreementConditions + .OrderBy(x => x.RentalAgreementConditionId) + .ToList(); - if (!string.IsNullOrEmpty(tempAddress) && !string.IsNullOrEmpty(agreement.Equipment.Owner.Province)) - tempAddress = $"{tempAddress}, {agreement.Equipment.Owner.Province}"; + docModel.RentalAgreementRates = agreement.RentalAgreementRates.Where(x => x.Active).ToList(); + docModel.Status = agreement.RentalAgreementStatusType.Description; + docModel.ConditionsPresent = agreement.RentalAgreementConditions.Count > 0; - if (string.IsNullOrEmpty(tempAddress) && !string.IsNullOrEmpty(agreement.Equipment.Owner.PostalCode)) - tempAddress = $"{agreement.Equipment.Owner.PostalCode}"; + foreach (var condition in docModel.RentalAgreementConditions) + { + if (!string.IsNullOrEmpty(condition.Comment)) + { + condition.ConditionName = condition.Comment; + } + } - if (!string.IsNullOrEmpty(tempAddress) && !string.IsNullOrEmpty(agreement.Equipment.Owner.PostalCode)) - tempAddress = $"{tempAddress} {agreement.Equipment.Owner.PostalCode}"; + docModel = CalculateTotals(docModel); - agreement.Equipment.Owner.Address2 = tempAddress; + // classification (Rental Agreement) + docModel.Classification = $"23010-30/{agreement.Number}"; - // format the note - if (!string.IsNullOrEmpty(agreement.Note)) - { - string temp = Regex.Replace(agreement.Note, @"\n", "
"); - string[] tempArray = temp.Split("
"); + return docModel; + } - docModel.Note = new List(); + private static string FormatOwnerAddress(RentalAgreementDto agreement) + { + // format owner address + string tempAddress = agreement.Equipment.Owner.Address2; - foreach (string row in tempArray) - { - NoteLine line = new NoteLine { Line = row }; - docModel.Note.Add(line); - } - } + if (string.IsNullOrEmpty(tempAddress) && !string.IsNullOrEmpty(agreement.Equipment.Owner.City)) + tempAddress = $"{agreement.Equipment.Owner.City}"; - // ensure they are ordered the way they were added - docModel.RentalAgreementConditions = agreement.RentalAgreementConditions - .OrderBy(x => x.RentalAgreementConditionId) - .ToList(); + if (!string.IsNullOrEmpty(tempAddress) + && !string.IsNullOrEmpty(agreement.Equipment.Owner.City) + && agreement.Equipment.Owner.City.Trim() != tempAddress.Trim()) + { + tempAddress = $"{tempAddress}, {agreement.Equipment.Owner.City}"; + } - docModel.RentalAgreementRates = agreement.RentalAgreementRates.Where(x => x.Active).ToList(); - docModel.Status = agreement.RentalAgreementStatusType.Description; - docModel.ConditionsPresent = agreement.RentalAgreementConditions.Count > 0; + if (string.IsNullOrEmpty(tempAddress) && !string.IsNullOrEmpty(agreement.Equipment.Owner.Province)) + tempAddress = $"{agreement.Equipment.Owner.Province}"; - foreach (var condition in docModel.RentalAgreementConditions) - { - if (!string.IsNullOrEmpty(condition.Comment)) - { - condition.ConditionName = condition.Comment; - } - } + if (!string.IsNullOrEmpty(tempAddress) && !string.IsNullOrEmpty(agreement.Equipment.Owner.Province)) + tempAddress = $"{tempAddress}, {agreement.Equipment.Owner.Province}"; - docModel = CalculateTotals(docModel); + if (string.IsNullOrEmpty(tempAddress) && !string.IsNullOrEmpty(agreement.Equipment.Owner.PostalCode)) + tempAddress = $"{agreement.Equipment.Owner.PostalCode}"; - // classification (Rental Agreement) - docModel.Classification = $"23010-30/{agreement.Number}"; - } + if (!string.IsNullOrEmpty(tempAddress) && !string.IsNullOrEmpty(agreement.Equipment.Owner.PostalCode)) + tempAddress = $"{tempAddress} {agreement.Equipment.Owner.PostalCode}"; - return docModel; + return tempAddress; } - private string ConvertDate(DateTime? dateObject) + private static string ConvertDate(DateTime? dateObject) { string result = ""; - if (dateObject != null) + if (dateObject is DateTime dateObj) { // since the PDF template is raw HTML and won't convert a date object, we must adjust the time zone here TimeZoneInfo tzi; @@ -289,18 +301,7 @@ private string ConvertDate(DateTime? dateObject) } } - DateTime dt; - - if (tzi != null) - { - dt = TimeZoneInfo.ConvertTime((DateTime)dateObject, tzi); - - } - else - { - dt = (DateTime)dateObject; - - } + DateTime dt = tzi != null ? TimeZoneInfo.ConvertTime(dateObj, tzi) : dateObj; result = dt.ToString("yyyy-MMM-dd").ToUpper(); } diff --git a/Server/HetsData/Repositories/RentalRequestRepository.cs b/Server/HetsData/Repositories/RentalRequestRepository.cs index 3a28069d4..60fdc0ce2 100644 --- a/Server/HetsData/Repositories/RentalRequestRepository.cs +++ b/Server/HetsData/Repositories/RentalRequestRepository.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Configuration; using System; using System.Linq; +using HetsCommon; namespace HetsData.Repositories { @@ -64,8 +65,13 @@ public RentalRequestLite ToLiteModel(HetRentalRequest request) requestLite.Status = request.RentalRequestStatusType.Description; requestLite.EquipmentCount = request.EquipmentCount; - requestLite.ExpectedEndDate = request.ExpectedEndDate; - requestLite.ExpectedStartDate = request.ExpectedStartDate; + requestLite.ExpectedEndDate = + request.ExpectedEndDate is DateTime expectedEndDateUtc ? + DateUtils.AsUTC(expectedEndDateUtc) : null; + + requestLite.ExpectedStartDate = + request.ExpectedStartDate is DateTime expectedStartDateUtc ? + DateUtils.AsUTC(expectedStartDateUtc) : null; } return requestLite; @@ -119,7 +125,7 @@ public RentalRequestDto GetRecordWithRotationList(int id, SeniorityScoringRules .FirstOrDefault(a => a.RentalRequestId == id); //pull out the date that request was last updated - var requestDate = request.AppLastUpdateTimestamp; + var requestDate = DateUtils.AsUTC(request.AppLastUpdateTimestamp); foreach (var rrrl in request.HetRentalRequestRotationLists) { @@ -190,7 +196,17 @@ public RentalRequestDto GetRecordWithRotationList(int id, SeniorityScoringRules } } } - + // TH-112626 + // Sorting the RentalRequestRotationList based on Equipment.Seniority + var sortedList = request.HetRentalRequestRotationLists + .OrderByDescending(x => x.Equipment.Seniority) + .ToList(); + // Updating RotationListSortOrder based on the sorted list + for (int i = 0; i < sortedList.Count; i++) + { + sortedList[i].RotationListSortOrder = i + 1; + } + request.HetRentalRequestRotationLists = sortedList; return _mapper.Map(request); } diff --git a/Server/HetsImport/Import/ImportEquipUsage.cs b/Server/HetsImport/Import/ImportEquipUsage.cs index 661db74df..a5cf208b8 100644 --- a/Server/HetsImport/Import/ImportEquipUsage.cs +++ b/Server/HetsImport/Import/ImportEquipUsage.cs @@ -11,6 +11,7 @@ using Hangfire.Console.Progress; using HetsData.Helpers; using HetsData.Model; +using HetsCommon; namespace HetsImport.Import { @@ -228,14 +229,16 @@ private static void CopyToTimeRecorded(DbAppContext dbContext, ImportModels.Equi // so ignore all others // *********************************************** DateTime fiscalStart; - - if (DateTime.UtcNow.Month == 1 || DateTime.UtcNow.Month == 2 || DateTime.UtcNow.Month == 3) + DateTime now = DateTime.Now; + if (now.Month == 1 || now.Month == 2 || now.Month == 3) { - fiscalStart = new DateTime(DateTime.UtcNow.AddYears(-1).Year, 4, 1); + fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.AddYears(-1).Year, 4, 1, 0, 0, 0)); } else { - fiscalStart = new DateTime(DateTime.UtcNow.Year, 4, 1); + fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.Year, 4, 1, 0, 0, 0)); } string tempRecordDate = oldObject.Worked_Dt; diff --git a/Server/HetsImport/Import/ImportRotationDoc.cs b/Server/HetsImport/Import/ImportRotationDoc.cs index c8de33f41..df09e6d98 100644 --- a/Server/HetsImport/Import/ImportRotationDoc.cs +++ b/Server/HetsImport/Import/ImportRotationDoc.cs @@ -10,6 +10,7 @@ using Hangfire.Server; using HetsData.Helpers; using HetsData.Model; +using HetsCommon; namespace HetsImport.Import { @@ -141,14 +142,16 @@ private static void CopyToInstance(DbAppContext dbContext, ImportModels.Rotation // so ignore all others // *********************************************** DateTime fiscalStart; - - if (DateTime.UtcNow.Month == 1 || DateTime.UtcNow.Month == 2 || DateTime.UtcNow.Month == 3) + DateTime now = DateTime.Now; + if (now.Month == 1 || now.Month == 2 || now.Month == 3) { - fiscalStart = new DateTime(DateTime.UtcNow.AddYears(-1).Year, 4, 1); + fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.AddYears(-1).Year, 4, 1, 0, 0, 0)); } else { - fiscalStart = new DateTime(DateTime.UtcNow.Year, 4, 1); + fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.Year, 4, 1, 0, 0, 0)); } // *********************************************** diff --git a/Server/HetsImport/Import/ImportServiceArea.cs b/Server/HetsImport/Import/ImportServiceArea.cs index 9c0539529..7ea7ab9e1 100644 --- a/Server/HetsImport/Import/ImportServiceArea.cs +++ b/Server/HetsImport/Import/ImportServiceArea.cs @@ -10,6 +10,7 @@ using Hangfire.Server; using Hangfire.Console.Progress; using HetsData.Model; +using HetsCommon; namespace HetsImport.Import { @@ -82,14 +83,16 @@ public static void ResetDistrictStatus(PerformContext performContext, DbAppConte // determine the current fiscal year DateTime fiscalStart; - - if (DateTime.UtcNow.Month == 1 || DateTime.UtcNow.Month == 2 || DateTime.UtcNow.Month == 3) + DateTime now = DateTime.Now; + if (now.Month == 1 || now.Month == 2 || now.Month == 3) { - fiscalStart = new DateTime(DateTime.UtcNow.AddYears(-1).Year, 4, 1); + fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.AddYears(-1).Year, 4, 1, 0, 0, 0)); } else { - fiscalStart = new DateTime(DateTime.UtcNow.Year, 4, 1); + fiscalStart = DateUtils.ConvertPacificToUtcTime( + new DateTime(now.Year, 4, 1, 0, 0, 0)); } if (dbContext.HetDistrict.Any()) diff --git a/Server/HetsReport/Helpers/SecurityHelper.cs b/Server/HetsReport/Helpers/SecurityHelper.cs index abf6ea36e..b0b2bd800 100644 --- a/Server/HetsReport/Helpers/SecurityHelper.cs +++ b/Server/HetsReport/Helpers/SecurityHelper.cs @@ -20,8 +20,10 @@ public static void PasswordProtect(WordprocessingDocument wordDocument, Action Word requires that the initial hash of the password with the salt not be considered in the count // The initial hash of salt + key is not included in the iteration count - HashAlgorithm sha1 = new SHA1Managed(); - generatedKey = sha1.ComputeHash(generatedKey); + generatedKey = SHA1.HashData(generatedKey); byte[] iterator = new byte[4]; for (int intTmp = 0; intTmp < iterations; intTmp++) @@ -131,7 +132,7 @@ public static void PasswordProtect(WordprocessingDocument wordDocument, Action> 24); generatedKey = ConcatByteArrays(iterator, generatedKey); - generatedKey = sha1.ComputeHash(generatedKey); + generatedKey = SHA1.HashData(generatedKey); } DocumentProtection documentProtection = new DocumentProtection { Edit = DocumentProtectionValues.ReadOnly }; @@ -155,7 +156,7 @@ public static void PasswordProtect(WordprocessingDocument wordDocument, Action + - net5.0 + net7.0 1.9.3.0 @@ -20,7 +20,7 @@
- + diff --git a/Server/HetsReport/OwnerVerification.cs b/Server/HetsReport/OwnerVerification.cs index 5773480b5..0f6fe8f9c 100644 --- a/Server/HetsReport/OwnerVerification.cs +++ b/Server/HetsReport/OwnerVerification.cs @@ -185,7 +185,6 @@ public static byte[] GetOwnerVerification(OwnerVerificationReportModel reportMod wordDocument = (WordprocessingDocument) ownerDocument.Clone(documentStream); - ownerDocument.Close(); ownerDocument.Dispose(); } else @@ -248,7 +247,6 @@ public static byte[] GetOwnerVerification(OwnerVerificationReportModel reportMod AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId); - ownerDocument.Close(); ownerDocument.Dispose(); ownerStream.Seek(0, SeekOrigin.Begin); @@ -266,7 +264,6 @@ public static byte[] GetOwnerVerification(OwnerVerificationReportModel reportMod } } - wordTemplate.Close(); wordTemplate.Dispose(); templateStream.Close(); } @@ -277,7 +274,6 @@ public static byte[] GetOwnerVerification(OwnerVerificationReportModel reportMod wordDocument.CompressionOption = CompressionOption.Maximum; SecurityHelper.PasswordProtect(wordDocument, logErrorAction); - wordDocument.Close(); wordDocument.Dispose(); documentStream.Seek(0, SeekOrigin.Begin); diff --git a/Server/HetsReport/RentalAgreement.cs b/Server/HetsReport/RentalAgreement.cs index 024d11f4c..45db2cb69 100644 --- a/Server/HetsReport/RentalAgreement.cs +++ b/Server/HetsReport/RentalAgreement.cs @@ -207,11 +207,9 @@ public static byte[] GetRentalAgreement(RentalAgreementDocViewModel reportModel, wordDocument = (WordprocessingDocument) agreementDocument.Clone(documentStream); - agreementDocument.Close(); agreementDocument.Dispose(); } - wordTemplate.Close(); wordTemplate.Dispose(); templateStream.Close(); } @@ -222,7 +220,6 @@ public static byte[] GetRentalAgreement(RentalAgreementDocViewModel reportModel, wordDocument.CompressionOption = CompressionOption.Maximum; SecurityHelper.PasswordProtect(wordDocument, logErrorAction); - wordDocument.Close(); wordDocument.Dispose(); documentStream.Seek(0, SeekOrigin.Begin); diff --git a/Server/HetsReport/SeniorityList.cs b/Server/HetsReport/SeniorityList.cs index d034a213b..dc37a03cf 100644 --- a/Server/HetsReport/SeniorityList.cs +++ b/Server/HetsReport/SeniorityList.cs @@ -127,8 +127,6 @@ public static byte[] GetSeniorityList(SeniorityListReportViewModel reportModel, } wordDocument = (WordprocessingDocument)listDocument.Clone(documentStream); - - listDocument.Close(); listDocument.Dispose(); } else @@ -176,7 +174,6 @@ public static byte[] GetSeniorityList(SeniorityListReportViewModel reportModel, AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId); - listDocument.Close(); listDocument.Dispose(); listStream.Seek(0, SeekOrigin.Begin); @@ -194,7 +191,6 @@ public static byte[] GetSeniorityList(SeniorityListReportViewModel reportModel, } } - wordTemplate.Close(); wordTemplate.Dispose(); templateStream.Close(); } @@ -205,7 +201,6 @@ public static byte[] GetSeniorityList(SeniorityListReportViewModel reportModel, wordDocument.CompressionOption = CompressionOption.Maximum; SecurityHelper.PasswordProtect(wordDocument, logErrorAction); - wordDocument.Close(); wordDocument.Dispose(); documentStream.Seek(0, SeekOrigin.Begin); diff --git a/client/.gitignore b/client/.gitignore index 800f3a80c..4486925f5 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -7,6 +7,7 @@ # testing /coverage +cypress.env.json # production /build diff --git a/client/package-lock.json b/client/package-lock.json index 0f788db6f..1f1125005 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -12,9 +12,9 @@ "@fortawesome/free-regular-svg-icons": "^5.15.3", "@fortawesome/free-solid-svg-icons": "^5.15.3", "@fortawesome/react-fontawesome": "^0.1.14", - "@testing-library/jest-dom": "^5.14.1", + "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^11.2.7", - "@testing-library/user-event": "^12.8.3", + "@testing-library/user-event": "^14.4.3", "bootstrap": "^4.6.0", "classnames": "^2.2.6", "file-saver": "^2.0.5", @@ -23,6 +23,7 @@ "keycloak-js": "^19.0.2", "lodash": "^4.17.21", "moment": "^2.22.2", + "msw": "^1.2.1", "react": "^17.0.2", "react-bootstrap": "^1.6.1", "react-datetime": "^3.0.4", @@ -41,6 +42,11 @@ "sass": "^1.58.0" } }, + "node_modules/@adobe/css-tools": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", + "integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==" + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -3165,6 +3171,44 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "node_modules/@mswjs/cookies": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz", + "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==", + "dependencies": { + "@types/set-cookie-parser": "^2.4.0", + "set-cookie-parser": "^2.4.6" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@mswjs/interceptors": { + "version": "0.17.9", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.9.tgz", + "integrity": "sha512-4LVGt03RobMH/7ZrbHqRxQrS9cc2uh+iNKSj8UWr8M26A2i793ju+csaB5zaqYltqJmA2jUq4VeYfKmVqvsXQg==", + "dependencies": { + "@open-draft/until": "^1.0.3", + "@types/debug": "^4.1.7", + "@xmldom/xmldom": "^0.8.3", + "debug": "^4.3.3", + "headers-polyfill": "^3.1.0", + "outvariant": "^1.2.1", + "strict-event-emitter": "^0.2.4", + "web-encoding": "^1.1.5" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@mswjs/interceptors/node_modules/strict-event-emitter": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz", + "integrity": "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==", + "dependencies": { + "events": "^3.3.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3258,6 +3302,11 @@ "node": ">=10" } }, + "node_modules/@open-draft/until": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz", + "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==" + }, "node_modules/@popperjs/core": { "version": "2.11.6", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", @@ -3641,27 +3690,38 @@ } }, "node_modules/@testing-library/dom": { - "version": "7.31.2", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", - "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.2.0.tgz", + "integrity": "sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA==", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", + "@types/aria-query": "^5.0.1", + "aria-query": "^5.0.0", "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.6", - "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" }, "engines": { - "node": ">=10" + "node": ">=14" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "peer": true, + "dependencies": { + "deep-equal": "^2.0.5" } }, "node_modules/@testing-library/dom/node_modules/chalk": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3673,16 +3733,42 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/@testing-library/jest-dom": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", - "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", + "version": "5.16.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", + "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", "dependencies": { + "@adobe/css-tools": "^4.0.1", "@babel/runtime": "^7.9.2", "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^4.2.2", + "aria-query": "^5.0.0", "chalk": "^3.0.0", - "css": "^3.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.5.6", "lodash": "^4.17.15", @@ -3694,6 +3780,14 @@ "yarn": ">=1" } }, + "node_modules/@testing-library/jest-dom/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, "node_modules/@testing-library/react": { "version": "11.2.7", "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.7.tgz", @@ -3710,15 +3804,50 @@ "react-dom": "*" } }, - "node_modules/@testing-library/user-event": { - "version": "12.8.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.8.3.tgz", - "integrity": "sha512-IR0iWbFkgd56Bu5ZI/ej8yQwrkCv8Qydx6RzwbKz9faXazR/+5tvYKsZQgyXJiwgpcva127YO6JcWy7YlCfofQ==", + "node_modules/@testing-library/react/node_modules/@testing-library/dom": { + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", "dependencies": { - "@babel/runtime": "^7.12.5" + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.6", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" }, "engines": { - "node": ">=10", + "node": ">=10" + } + }, + "node_modules/@testing-library/react/node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==" + }, + "node_modules/@testing-library/react/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.4.3", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", + "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", + "engines": { + "node": ">=12", "npm": ">=6" }, "peerDependencies": { @@ -3744,9 +3873,10 @@ } }, "node_modules/@types/aria-query": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz", - "integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", + "peer": true }, "node_modules/@types/babel__core": { "version": "7.1.19", @@ -3827,6 +3957,19 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/eslint": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", @@ -3934,6 +4077,11 @@ "pretty-format": "^26.0.0" } }, + "node_modules/@types/js-levenshtein": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz", + "integrity": "sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==" + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -3960,6 +4108,11 @@ "optional": true, "peer": true }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, "node_modules/@types/node": { "version": "15.12.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.0.tgz", @@ -4065,6 +4218,14 @@ "@types/node": "*" } }, + "node_modules/@types/set-cookie-parser": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz", + "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/sockjs": { "version": "0.3.33", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", @@ -4522,6 +4683,14 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.7.tgz", + "integrity": "sha512-sI1Ly2cODlWStkINzqGrZ8K6n+MTSbAeQnAipGyL+KZCXuHaRlj2gyyy8B/9MvsFFqN7XHryQnB2QwhzvJXovg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -4534,6 +4703,12 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, + "node_modules/@zxing/text-encoding": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", + "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", + "optional": true + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -4778,7 +4953,6 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, "dependencies": { "type-fest": "^0.21.3" }, @@ -4793,7 +4967,6 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, "engines": { "node": ">=10" }, @@ -4839,7 +5012,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -5080,17 +5252,6 @@ "node": ">= 4.0.0" } }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, "node_modules/autoprefixer": { "version": "10.4.7", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.7.tgz", @@ -5124,6 +5285,17 @@ "postcss": "^8.1.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -5491,11 +5663,33 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, "engines": { "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -5682,6 +5876,29 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -5758,7 +5975,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -5898,6 +6114,11 @@ "node": ">=6" } }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, "node_modules/check-types": { "version": "11.1.2", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", @@ -5908,7 +6129,6 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, "funding": [ { "type": "individual", @@ -5935,7 +6155,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -6003,6 +6222,36 @@ "node": ">=6" } }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.8.0.tgz", + "integrity": "sha512-/eG5sJcvEIwxcdYM86k5tPwn0MUzkX5YY3eImTGpJOZgVe4SdTMY14vQpcxgBzJ0wXwAYrS8E+c3uHeK4JNyzQ==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -6014,6 +6263,14 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -6436,16 +6693,6 @@ "node": ">=8" } }, - "node_modules/css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", - "dependencies": { - "inherits": "^2.0.4", - "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" - } - }, "node_modules/css-blank-pseudo": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", @@ -6889,7 +7136,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -6945,20 +7191,44 @@ "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "dev": true }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "engines": { - "node": ">=0.10" - } - }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, + "node_modules/deep-equal": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", + "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", + "dependencies": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, "node_modules/deep-freeze-strict": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-freeze-strict/-/deep-freeze-strict-1.1.1.tgz", @@ -6991,6 +7261,17 @@ "node": ">= 10" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -7004,7 +7285,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -7193,9 +7473,9 @@ } }, "node_modules/dom-accessibility-api": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz", - "integrity": "sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==" + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" }, "node_modules/dom-converter": { "version": "0.2.0", @@ -7401,7 +7681,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "peer": true, "dependencies": { @@ -7510,6 +7789,30 @@ "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", "dev": true }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, "node_modules/es-module-lexer": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", @@ -7546,7 +7849,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -8276,7 +8578,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, "engines": { "node": ">=0.8.x" } @@ -8493,6 +8794,30 @@ "optional": true, "peer": true }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -8580,6 +8905,20 @@ "bser": "2.1.1" } }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -8810,6 +9149,14 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -9038,7 +9385,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -9051,8 +9397,7 @@ "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/function.prototype.name": { "version": "1.1.5", @@ -9082,7 +9427,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9136,16 +9480,14 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -9341,12 +9683,31 @@ "node": ">= 0.10" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, + "node_modules/graphql": { + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", + "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, "node_modules/gzip-size": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", @@ -9416,7 +9777,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -9428,7 +9788,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9445,7 +9804,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.1" }, @@ -9457,7 +9815,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -9469,7 +9826,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -9497,6 +9853,11 @@ "he": "bin/he" } }, + "node_modules/headers-polyfill": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.1.2.tgz", + "integrity": "sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==" + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -9775,7 +10136,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, + "devOptional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -9813,6 +10174,25 @@ "node": ">=4" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -9927,13 +10307,52 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "node_modules/inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", "dependencies": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.2.0", "has": "^1.0.3", "side-channel": "^1.0.4" }, @@ -9966,6 +10385,34 @@ "node": ">= 10" } }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -9976,7 +10423,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, "dependencies": { "has-bigints": "^1.0.1" }, @@ -9988,7 +10434,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -10000,7 +10445,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -10016,7 +10460,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -10040,7 +10483,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -10078,7 +10520,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -10092,6 +10533,20 @@ "node": ">=6" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -10103,6 +10558,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, "node_modules/is-lambda": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", @@ -10111,6 +10574,14 @@ "optional": true, "peer": true }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -10129,6 +10600,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==" + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -10141,7 +10617,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -10182,7 +10657,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -10212,11 +10686,18 @@ "node": ">=6" } }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -10240,7 +10721,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -10255,7 +10735,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -10266,12 +10745,49 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -10284,6 +10800,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -12523,6 +13051,14 @@ "optional": true, "peer": true }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/js-sha256": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", @@ -12875,6 +13411,36 @@ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", "dev": true }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -12908,9 +13474,9 @@ } }, "node_modules/lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "bin": { "lz-string": "bin/bin.js" } @@ -13196,7 +13762,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, "engines": { "node": ">=6" } @@ -13472,8 +14037,129 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/msw": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/msw/-/msw-1.2.1.tgz", + "integrity": "sha512-bF7qWJQSmKn6bwGYVPXOxhexTCGD5oJSZg8yt8IBClxvo3Dx/1W0zqE1nX9BSWmzRsCKWfeGWcB/vpqV6aclpw==", + "hasInstallScript": true, + "dependencies": { + "@mswjs/cookies": "^0.2.2", + "@mswjs/interceptors": "^0.17.5", + "@open-draft/until": "^1.0.3", + "@types/cookie": "^0.4.1", + "@types/js-levenshtein": "^1.1.1", + "chalk": "4.1.1", + "chokidar": "^3.4.2", + "cookie": "^0.4.2", + "graphql": "^15.0.0 || ^16.0.0", + "headers-polyfill": "^3.1.2", + "inquirer": "^8.2.0", + "is-node-process": "^1.2.0", + "js-levenshtein": "^1.1.6", + "node-fetch": "^2.6.7", + "outvariant": "^1.4.0", + "path-to-regexp": "^6.2.0", + "strict-event-emitter": "^0.4.3", + "type-fest": "^2.19.0", + "yargs": "^17.3.1" + }, + "bin": { + "msw": "cli/index.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.4.x <= 5.0.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/msw/node_modules/chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/msw/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/msw/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/msw/node_modules/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + }, + "node_modules/msw/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/msw/node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/msw/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -13488,6 +14174,11 @@ "multicast-dns": "cli.js" } }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, "node_modules/nan": { "version": "2.14.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", @@ -13539,6 +14230,44 @@ "tslib": "^2.0.3" } }, + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -13757,7 +14486,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -13859,7 +14587,21 @@ "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -13868,20 +14610,18 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { @@ -14010,7 +14750,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -14055,6 +14794,56 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/outvariant": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz", + "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==" + }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -16586,7 +17375,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -16689,7 +17477,6 @@ "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -16849,7 +17636,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -16976,6 +17762,18 @@ "node": ">=10" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -17065,6 +17863,14 @@ "randombytes": "^2.1.0" } }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -17088,17 +17894,23 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sanitize.css": { "version": "13.0.0", @@ -17464,6 +18276,11 @@ "optional": true, "peer": true }, + "node_modules/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -17480,7 +18297,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -17493,8 +18309,7 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/sisteransi": { "version": "1.0.5", @@ -17585,6 +18400,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -17619,16 +18435,6 @@ "webpack": "^5.0.0" } }, - "node_modules/source-map-resolve": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" - } - }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -17829,11 +18635,26 @@ "readable-stream": "^2.0.1" } }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/strict-event-emitter": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz", + "integrity": "sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==" + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -17861,7 +18682,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -17874,8 +18694,7 @@ "node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string.prototype.matchall": { "version": "4.0.7", @@ -17942,7 +18761,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -18480,6 +19298,11 @@ "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", "dev": true }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -18496,6 +19319,17 @@ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -18630,8 +19464,7 @@ "node_modules/tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -18734,7 +19567,7 @@ "version": "4.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", - "dev": true, + "devOptional": true, "peer": true, "bin": { "tsc": "bin/tsc", @@ -18890,11 +19723,22 @@ "punycode": "^2.1.0" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "node_modules/util.promisify": { "version": "1.0.1", @@ -19069,6 +19913,25 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-encoding": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", + "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", + "dependencies": { + "util": "^0.12.3" + }, + "optionalDependencies": { + "@zxing/text-encoding": "0.9.0" + } + }, "node_modules/web-vitals": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-1.1.2.tgz", @@ -19498,7 +20361,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -19510,6 +20372,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -19846,7 +20741,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -19923,7 +20817,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "engines": { "node": ">=10" } @@ -19984,6 +20877,11 @@ } }, "dependencies": { + "@adobe/css-tools": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", + "integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==" + }, "@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -22215,6 +23113,40 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "@mswjs/cookies": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz", + "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==", + "requires": { + "@types/set-cookie-parser": "^2.4.0", + "set-cookie-parser": "^2.4.6" + } + }, + "@mswjs/interceptors": { + "version": "0.17.9", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.9.tgz", + "integrity": "sha512-4LVGt03RobMH/7ZrbHqRxQrS9cc2uh+iNKSj8UWr8M26A2i793ju+csaB5zaqYltqJmA2jUq4VeYfKmVqvsXQg==", + "requires": { + "@open-draft/until": "^1.0.3", + "@types/debug": "^4.1.7", + "@xmldom/xmldom": "^0.8.3", + "debug": "^4.3.3", + "headers-polyfill": "^3.1.0", + "outvariant": "^1.2.1", + "strict-event-emitter": "^0.2.4", + "web-encoding": "^1.1.5" + }, + "dependencies": { + "strict-event-emitter": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz", + "integrity": "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==", + "requires": { + "events": "^3.3.0" + } + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -22288,6 +23220,11 @@ } } }, + "@open-draft/until": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz", + "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==" + }, "@popperjs/core": { "version": "2.11.6", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", @@ -22534,45 +23471,85 @@ } }, "@testing-library/dom": { - "version": "7.31.2", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", - "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.2.0.tgz", + "integrity": "sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA==", + "peer": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", + "@types/aria-query": "^5.0.1", + "aria-query": "^5.0.0", "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.6", - "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" }, "dependencies": { + "aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "peer": true, + "requires": { + "deep-equal": "^2.0.5" + } + }, "chalk": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "peer": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "peer": true + } + } } } }, "@testing-library/jest-dom": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", - "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", + "version": "5.16.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", + "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", "requires": { + "@adobe/css-tools": "^4.0.1", "@babel/runtime": "^7.9.2", "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^4.2.2", + "aria-query": "^5.0.0", "chalk": "^3.0.0", - "css": "^3.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.5.6", "lodash": "^4.17.15", "redent": "^3.0.0" + }, + "dependencies": { + "aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "requires": { + "deep-equal": "^2.0.5" + } + } } }, "@testing-library/react": { @@ -22582,15 +23559,44 @@ "requires": { "@babel/runtime": "^7.12.5", "@testing-library/dom": "^7.28.1" + }, + "dependencies": { + "@testing-library/dom": { + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.6", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" + } + }, + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "@testing-library/user-event": { - "version": "12.8.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.8.3.tgz", - "integrity": "sha512-IR0iWbFkgd56Bu5ZI/ej8yQwrkCv8Qydx6RzwbKz9faXazR/+5tvYKsZQgyXJiwgpcva127YO6JcWy7YlCfofQ==", - "requires": { - "@babel/runtime": "^7.12.5" - } + "version": "14.4.3", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", + "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", + "requires": {} }, "@tootallnate/once": { "version": "1.1.2", @@ -22605,9 +23611,10 @@ "dev": true }, "@types/aria-query": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz", - "integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", + "peer": true }, "@types/babel__core": { "version": "7.1.19", @@ -22688,6 +23695,19 @@ "@types/node": "*" } }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "requires": { + "@types/ms": "*" + } + }, "@types/eslint": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", @@ -22795,6 +23815,11 @@ "pretty-format": "^26.0.0" } }, + "@types/js-levenshtein": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz", + "integrity": "sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==" + }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -22821,6 +23846,11 @@ "optional": true, "peer": true }, + "@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, "@types/node": { "version": "15.12.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.0.tgz", @@ -22926,6 +23956,14 @@ "@types/node": "*" } }, + "@types/set-cookie-parser": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz", + "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==", + "requires": { + "@types/node": "*" + } + }, "@types/sockjs": { "version": "0.3.33", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", @@ -23272,6 +24310,11 @@ "@xtuc/long": "4.2.2" } }, + "@xmldom/xmldom": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.7.tgz", + "integrity": "sha512-sI1Ly2cODlWStkINzqGrZ8K6n+MTSbAeQnAipGyL+KZCXuHaRlj2gyyy8B/9MvsFFqN7XHryQnB2QwhzvJXovg==" + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -23284,6 +24327,12 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, + "@zxing/text-encoding": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", + "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", + "optional": true + }, "abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -23473,7 +24522,6 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, "requires": { "type-fest": "^0.21.3" }, @@ -23481,8 +24529,7 @@ "type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" } } }, @@ -23509,7 +24556,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -23701,11 +24747,6 @@ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, "autoprefixer": { "version": "10.4.7", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.7.tgz", @@ -23720,6 +24761,11 @@ "postcss-value-parser": "^4.2.0" } }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -24009,8 +25055,29 @@ "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } }, "bluebird": { "version": "3.7.2", @@ -24155,6 +25222,15 @@ "node-int64": "^0.4.0" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -24215,7 +25291,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -24315,6 +25390,11 @@ "integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==", "dev": true }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, "check-types": { "version": "11.1.2", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", @@ -24325,7 +25405,6 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -24341,7 +25420,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -24396,6 +25474,24 @@ "optional": true, "peer": true }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.8.0.tgz", + "integrity": "sha512-/eG5sJcvEIwxcdYM86k5tPwn0MUzkX5YY3eImTGpJOZgVe4SdTMY14vQpcxgBzJ0wXwAYrS8E+c3uHeK4JNyzQ==" + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -24407,6 +25503,11 @@ "wrap-ansi": "^7.0.0" } }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -24741,16 +25842,6 @@ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", "dev": true }, - "css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", - "requires": { - "inherits": "^2.0.4", - "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" - } - }, "css-blank-pseudo": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", @@ -25059,7 +26150,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -25100,17 +26190,43 @@ "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "dev": true }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, "dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, + "deep-equal": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", + "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", + "requires": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + } + } + }, "deep-freeze-strict": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-freeze-strict/-/deep-freeze-strict-1.1.1.tgz", @@ -25137,6 +26253,14 @@ "execa": "^5.0.0" } }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "requires": { + "clone": "^1.0.2" + } + }, "define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -25147,7 +26271,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, "requires": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -25291,9 +26414,9 @@ } }, "dom-accessibility-api": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz", - "integrity": "sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==" + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" }, "dom-converter": { "version": "0.2.0", @@ -25456,7 +26579,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "peer": true, "requires": { @@ -25550,6 +26672,29 @@ "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", "dev": true }, + "es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + } + } + }, "es-module-lexer": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", @@ -25579,8 +26724,7 @@ "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, "escape-html": { "version": "1.0.3", @@ -26115,8 +27259,7 @@ "events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, "execa": { "version": "5.1.1", @@ -26284,6 +27427,26 @@ "optional": true, "peer": true }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -26361,6 +27524,14 @@ "bser": "2.1.1" } }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -26535,6 +27706,14 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==" }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -26694,14 +27873,12 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "optional": true }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "function.prototype.name": { "version": "1.1.5", @@ -26724,8 +27901,7 @@ "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" }, "gauge": { "version": "3.0.2", @@ -26766,14 +27942,12 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -26920,12 +28094,25 @@ "minimatch": "~3.0.2" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, + "graphql": { + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", + "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==" + }, "gzip-size": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", @@ -26979,7 +28166,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -26987,8 +28173,7 @@ "has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" }, "has-flag": { "version": "4.0.0", @@ -26999,7 +28184,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, "requires": { "get-intrinsic": "^1.1.1" } @@ -27007,14 +28191,12 @@ "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, "has-tostringtag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -27033,6 +28215,11 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "headers-polyfill": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.1.2.tgz", + "integrity": "sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==" + }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -27253,7 +28440,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, + "devOptional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } @@ -27280,6 +28467,11 @@ "harmony-reflect": "^1.4.6" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -27365,13 +28557,45 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", "requires": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.2.0", "has": "^1.0.3", "side-channel": "^1.0.4" } @@ -27398,6 +28622,25 @@ "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", "dev": true }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -27408,7 +28651,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, "requires": { "has-bigints": "^1.0.1" } @@ -27417,7 +28659,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "requires": { "binary-extensions": "^2.0.0" } @@ -27426,7 +28667,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -27435,8 +28675,7 @@ "is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, "is-core-module": { "version": "2.9.0", @@ -27451,7 +28690,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -27470,8 +28708,7 @@ "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "is-generator-fn": { "version": "2.1.0", @@ -27479,6 +28716,14 @@ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -27487,6 +28732,11 @@ "is-extglob": "^2.1.1" } }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" + }, "is-lambda": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", @@ -27495,6 +28745,11 @@ "optional": true, "peer": true }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" + }, "is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -27507,6 +28762,11 @@ "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true }, + "is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==" + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -27516,7 +28776,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -27542,7 +28801,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -27560,11 +28818,15 @@ "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", "dev": true }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" + }, "is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, "requires": { "call-bind": "^1.0.2" } @@ -27579,7 +28841,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -27588,17 +28849,38 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, "requires": { "has-symbols": "^1.0.2" } }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" + }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -27608,6 +28890,15 @@ "call-bind": "^1.0.2" } }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -29369,6 +30660,11 @@ "optional": true, "peer": true }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==" + }, "js-sha256": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", @@ -29656,6 +30952,26 @@ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", "dev": true }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -29683,9 +30999,9 @@ } }, "lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==" }, "magic-string": { "version": "0.25.9", @@ -29902,8 +31218,7 @@ "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, "min-indent": { "version": "1.0.1", @@ -30111,8 +31426,88 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "msw": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/msw/-/msw-1.2.1.tgz", + "integrity": "sha512-bF7qWJQSmKn6bwGYVPXOxhexTCGD5oJSZg8yt8IBClxvo3Dx/1W0zqE1nX9BSWmzRsCKWfeGWcB/vpqV6aclpw==", + "requires": { + "@mswjs/cookies": "^0.2.2", + "@mswjs/interceptors": "^0.17.5", + "@open-draft/until": "^1.0.3", + "@types/cookie": "^0.4.1", + "@types/js-levenshtein": "^1.1.1", + "chalk": "4.1.1", + "chokidar": "^3.4.2", + "cookie": "^0.4.2", + "graphql": "^15.0.0 || ^16.0.0", + "headers-polyfill": "^3.1.2", + "inquirer": "^8.2.0", + "is-node-process": "^1.2.0", + "js-levenshtein": "^1.1.6", + "node-fetch": "^2.6.7", + "outvariant": "^1.4.0", + "path-to-regexp": "^6.2.0", + "strict-event-emitter": "^0.4.3", + "type-fest": "^2.19.0", + "yargs": "^17.3.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + }, + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" + }, + "yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + } + } }, "multicast-dns": { "version": "7.2.5", @@ -30124,6 +31519,11 @@ "thunky": "^1.0.2" } }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, "nan": { "version": "2.14.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", @@ -30166,6 +31566,35 @@ "tslib": "^2.0.3" } }, + "node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -30341,8 +31770,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "normalize-range": { "version": "0.1.2", @@ -30416,24 +31844,30 @@ "object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" } }, @@ -30526,7 +31960,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, "requires": { "mimic-fn": "^2.1.0" } @@ -30556,6 +31989,43 @@ "word-wrap": "^1.2.3" } }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + }, + "outvariant": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz", + "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==" + }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -32274,7 +33744,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "requires": { "picomatch": "^2.2.1" } @@ -32363,7 +33832,6 @@ "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -32492,8 +33960,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-from-string": { "version": "2.0.2", @@ -32579,6 +34046,15 @@ "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", "dev": true }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, "retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -32645,6 +34121,11 @@ } } }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -32654,17 +34135,23 @@ "queue-microtask": "^1.2.2" } }, + "rxjs": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "requires": { + "tslib": "^2.1.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sanitize.css": { "version": "13.0.0", @@ -32957,6 +34444,11 @@ "optional": true, "peer": true }, + "set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -32973,7 +34465,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -32983,8 +34474,7 @@ "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "sisteransi": { "version": "1.0.5", @@ -33059,7 +34549,8 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true }, "source-map-js": { "version": "1.0.2", @@ -33078,15 +34569,6 @@ "source-map-js": "^1.0.1" } }, - "source-map-resolve": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" - } - }, "source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -33265,11 +34747,23 @@ "readable-stream": "^2.0.1" } }, + "stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "requires": { + "internal-slot": "^1.0.4" + } + }, + "strict-event-emitter": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz", + "integrity": "sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==" + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -33294,7 +34788,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -33304,8 +34797,7 @@ "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" } } }, @@ -33362,7 +34854,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -33755,6 +35246,11 @@ "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", "dev": true }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, "thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -33771,6 +35267,14 @@ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -33882,8 +35386,7 @@ "tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "tsutils": { "version": "3.21.0", @@ -33967,7 +35470,7 @@ "version": "4.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", - "dev": true, + "devOptional": true, "peer": true }, "unbox-primitive": { @@ -34085,11 +35588,22 @@ "punycode": "^2.1.0" } }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util.promisify": { "version": "1.0.1", @@ -34238,6 +35752,23 @@ "minimalistic-assert": "^1.0.0" } }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "requires": { + "defaults": "^1.0.3" + } + }, + "web-encoding": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", + "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", + "requires": { + "@zxing/text-encoding": "0.9.0", + "util": "^0.12.3" + } + }, "web-vitals": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-1.1.2.tgz", @@ -34550,7 +36081,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "requires": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -34559,6 +36089,30 @@ "is-symbol": "^1.0.3" } }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, "wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -34871,7 +36425,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -34924,8 +36477,7 @@ "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, "yallist": { "version": "4.0.0", diff --git a/client/package.json b/client/package.json index f85f9a4bd..afa17d38c 100644 --- a/client/package.json +++ b/client/package.json @@ -7,9 +7,9 @@ "@fortawesome/free-regular-svg-icons": "^5.15.3", "@fortawesome/free-solid-svg-icons": "^5.15.3", "@fortawesome/react-fontawesome": "^0.1.14", - "@testing-library/jest-dom": "^5.14.1", + "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^11.2.7", - "@testing-library/user-event": "^12.8.3", + "@testing-library/user-event": "^14.4.3", "bootstrap": "^4.6.0", "classnames": "^2.2.6", "file-saver": "^2.0.5", @@ -18,6 +18,7 @@ "keycloak-js": "^19.0.2", "lodash": "^4.17.21", "moment": "^2.22.2", + "msw": "^1.2.1", "react": "^17.0.2", "react-bootstrap": "^1.6.1", "react-datetime": "^3.0.4", diff --git a/client/src/App.test.js b/client/src/App.test.js deleted file mode 100644 index 1f03afeec..000000000 --- a/client/src/App.test.js +++ /dev/null @@ -1,8 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/client/src/index.js b/client/src/index.js index 68dc86dfb..420913d5c 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -5,7 +5,7 @@ import reportWebVitals from './reportWebVitals'; import * as Keycloak from './js/Keycloak'; import { Provider } from 'react-redux'; -import store from './js/store'; +import { store } from './js/store'; import 'bootstrap/dist/css/bootstrap.css'; import './sass/main.scss'; diff --git a/client/src/js/App.jsx b/client/src/js/App.jsx index 610ab702e..87aff93b9 100644 --- a/client/src/js/App.jsx +++ b/client/src/js/App.jsx @@ -9,7 +9,7 @@ import { ApiError } from './utils/http'; import * as Constant from './constants'; import * as Action from './actionTypes'; -import store from './store'; +import { store } from './store'; import { ProgressBar } from 'react-bootstrap'; import ErrorBoundary from './components/ErrorBoundary'; @@ -44,44 +44,44 @@ import FourOhFour from './views/404.jsx'; import addIconsToLibrary from './fontAwesome'; -export async function keepAlive() { +export const keepAlive = async () => { try { await keycloak.updateToken(70); } catch { console.log('Failed to refresh the token, or the session has expired'); } -} +}; window.setInterval(keepAlive, Constant.SESSION_KEEP_ALIVE_INTERVAL); -function showSessionTimoutDialog() { +const showSessionTimoutDialog = () => { store.dispatch({ type: Action.SHOW_SESSION_TIMEOUT_DIALOG }); -} +}; var sessionTimeoutTimer = window.setInterval(showSessionTimoutDialog, Constant.SESSION_TIMEOUT); -export function resetSessionTimeoutTimer() { +export const resetSessionTimeoutTimer = () => { window.clearInterval(sessionTimeoutTimer); sessionTimeoutTimer = window.setInterval(showSessionTimoutDialog, Constant.SESSION_TIMEOUT); -} +}; -export function getLookups(user) { +export const getLookups = (user) => (dispatch) => { if (user.businessUser) { return Promise.resolve(); - } else { - var districtId = user.district.id; - return Promise.all([ - Api.getDistricts(), - Api.getRegions(), - Api.getServiceAreas(), - Api.getLocalAreas(districtId), - Api.getFiscalYears(districtId), - Api.getPermissions(), - Api.getCurrentUserDistricts(), - Api.getFavourites(), - ]); } -} + + const districtId = user.district.id; + return Promise.all([ + dispatch(Api.getDistricts()), + dispatch(Api.getRegions()), + dispatch(Api.getServiceAreas()), + dispatch(Api.getLocalAreas(districtId)), + dispatch(Api.getFiscalYears(districtId)), + dispatch(Api.getPermissions()), + dispatch(Api.getCurrentUserDistricts()), + dispatch(Api.getFavourites()), + ]); +}; const Routes = (user) => { //render Routes based on user permissions @@ -257,7 +257,7 @@ const CommonRoutes = () => { //additional components const Unauthorized = () => <>Unauthorized; -const App = ({ user }) => { +const App = ({ user, dispatch }) => { const [loading, setLoading] = useState(true); const [apiError, setApiError] = useState(null); const [loadProgress, setLoadProgress] = useState(5); @@ -265,16 +265,16 @@ const App = ({ user }) => { useEffect(() => { addIconsToLibrary(); setLoadProgress(33); - Api.getCurrentUser() + dispatch(Api.getCurrentUser()) .then((user) => { setLoadProgress(75); - return getLookups(user); + return dispatch(getLookups(user)); }) .then(() => { setLoading(false); }) .catch((error) => { - console.log(error); + console.error(error); if (error instanceof ApiError) { setApiError(error.message); @@ -322,10 +322,10 @@ const App = ({ user }) => { ); }; -const mapStateToProps = (state) => { - return { - user: state.user, - }; -}; +const mapStateToProps = (state) => ({ + user: state.user, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps, null)(App); +export default connect(mapStateToProps, mapDispatchToProps)(App); diff --git a/client/src/js/App.test.jsx b/client/src/js/App.test.jsx new file mode 100644 index 000000000..a8f02b4af --- /dev/null +++ b/client/src/js/App.test.jsx @@ -0,0 +1,89 @@ +/* eslint-disable testing-library/no-node-access */ +/* eslint-disable testing-library/no-container */ +import { rest } from 'msw'; +import { setupServer } from "msw/node"; +import { waitFor } from '@testing-library/react'; + +import App from './App'; +import { keycloak } from './Keycloak'; +import { renderWithProviders } from './renderWithProviders'; +import { setupStore } from './store'; +import { getCurrentUser, getCurrentUserFavourites } from './mock/api/getCurrentUser'; +import { getRegions } from './mock/api/getRegions'; +import { getDistricts } from './mock/api/getDistricts'; +import { getServiceAreas } from './mock/api/getServiceAreas'; +import { getLocalAreas } from './mock/api/getLocalAreas'; +import { getFiscalYears } from './mock/api/getFiscalYears'; +import { getPermissions } from './mock/api/getPermissions'; +import { getUserDistricts } from './mock/api/getUserDistricts'; +import { getRolloverStatus } from './mock/api/getRolloverStatus'; +import { getCounts } from './mock/api/getCounts'; + +// Mock Keycloak service +const mockKeycloakUpdateToken = jest.spyOn(keycloak, "updateToken"); +mockKeycloakUpdateToken.mockResolvedValue(Promise.resolve(false)); + +const server = setupServer( + rest.get("/api/users/current", (_, res, ctx) => { + return res(ctx.json(getCurrentUser())); + }), + rest.get("/api/districts", (_, res, ctx) => { + return res(ctx.json(getDistricts())); + }), + rest.get("/api/regions", (_, res, ctx) => { + return res(ctx.json(getRegions())); + }), + rest.get("/api/serviceareas", (_, res, ctx) => { + return res(ctx.json(getServiceAreas())); + }), + rest.get("/api/districts/:district/localAreas", (_, res, ctx) => { + return res(ctx.json(getLocalAreas())); + }), + rest.get("/api/districts/:district/fiscalYears", (_, res, ctx) => { + return res(ctx.json(getFiscalYears())); + }), + rest.get("/api/permissions", (_, res, ctx) => { + return res(ctx.json(getPermissions())); + }), + rest.get("/api/userdistricts", (_, res, ctx) => { + return res(ctx.json(getUserDistricts())); + }), + rest.get("/api/users/current/favourites", (_, res, ctx) => { + return res(ctx.json(getCurrentUserFavourites())); + }), + rest.get("/api/districts/:district/rolloverStatus", (_, res, ctx) => { + return res(ctx.json(getRolloverStatus())); + }), + rest.get("/api/counts", (_, res, ctx) => { + return res(ctx.json(getCounts())); + }), +); + +let store; + +beforeAll(() => { + server.listen(); +}); + +beforeEach(() => { + store = setupStore(); +}) + +afterEach(() => { + server.resetHandlers(); +}); + +afterAll(() => { + server.close(); +}); + +test('renders main component', async () => { + const view = renderWithProviders(, { store }); + await waitFor(() => { + const loadingComponent = view.container.querySelector("#initialization"); + expect(loadingComponent).not.toBeInTheDocument(); + }); + + const mainComponent = view.container.querySelector("#main"); + expect(mainComponent).toBeInTheDocument(); +}); diff --git a/client/src/js/api.js b/client/src/js/api.js index cbde3459c..6c17658bc 100644 --- a/client/src/js/api.js +++ b/client/src/js/api.js @@ -2,7 +2,6 @@ import * as Action from './actionTypes'; import * as Constant from './constants'; import * as History from './history'; import * as Log from './history'; -import store from './store'; import { ApiRequest } from './utils/http'; import { lastFirstName, firstLastName, concat } from './utils/string'; @@ -11,15 +10,13 @@ import { daysAgo, sortableDateTime, today } from './utils/date'; import _ from 'lodash'; import Moment from 'moment'; -function normalize(response) { - return _.fromPairs(response.map((object) => [object.id, object])); -} +const normalize = (response) => _.fromPairs(response.map((object) => [object.id, object])); //////////////////// // Users //////////////////// -function parseUser(user) { +const parseUser = (user) => { if (!user.district) { user.district = { id: 0, name: '' }; } @@ -44,336 +41,308 @@ function parseUser(user) { user.canEdit = true; user.canDelete = true; -} +}; -export function getCurrentUser() { - return new ApiRequest('/users/current').get().then((response) => { - var user = response.data; +export const getCurrentUser = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/users/current').get()); + let user = response.data; + + // Add display fields + parseUser(user); - // Add display fields - parseUser(user); - - // Get permissions - var permissions = []; - _.each(user.userRoles, (userRole) => { - _.each(userRole.role.rolePermissions, (rolePermission) => { - permissions.push(rolePermission.permission.code); - }); + // Get permissions + const permissions = []; + _.each(user.userRoles, (userRole) => { + _.each(userRole.role.rolePermissions, (rolePermission) => { + permissions.push(rolePermission.permission.code); }); - user.permissions = _.uniq(permissions); - - user.hasPermission = function (permission) { - return user.permissions.indexOf(permission) !== -1; - }; - - store.dispatch({ type: Action.UPDATE_CURRENT_USER, user: user }); - return user; }); -} + user.permissions = _.uniq(permissions); + user.hasPermission = (permission) => user.permissions.indexOf(permission) !== -1; -export function searchUsers(params) { - store.dispatch({ type: Action.USERS_REQUEST }); - return new ApiRequest('/users/search').get(params).then((response) => { - var users = normalize(response.data); + dispatch({ type: Action.UPDATE_CURRENT_USER, user }); + return user; +}; - // Add display fields - _.map(users, (user) => { - parseUser(user); - }); +export const searchUsers = (params) => async (dispatch) => { + dispatch({ type: Action.USERS_REQUEST }); + const response = await dispatch(new ApiRequest('/users/search').get(params)); + let users = normalize(response.data); - store.dispatch({ type: Action.UPDATE_USERS, users: users }); + // Add display fields + _.map(users, (user) => { + parseUser(user); }); -} -export function getUsers() { - return new ApiRequest('/users').get().then((response) => { - var users = normalize(response.data); + dispatch({ type: Action.UPDATE_USERS, users }); +}; - // Add display fields - _.map(users, (user) => { - parseUser(user); - }); +export const getUsers = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/users').get()); + let users = normalize(response.data); - store.dispatch({ type: Action.UPDATE_USERS_LOOKUP, users: users }); + // Add display fields + _.map(users, (user) => { + parseUser(user); }); -} -export function getUser(userId) { - return new ApiRequest(`/users/${userId}`).get().then((response) => { - var user = response.data; + dispatch({ type: Action.UPDATE_USERS_LOOKUP, users }); +}; - // Add display fields - parseUser(user); +export const getUser = (userId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/users/${userId}`).get()); + let user = response.data; - store.dispatch({ type: Action.UPDATE_USER, user: user }); - }); -} + // Add display fields + parseUser(user); -export function addUser(user) { - return new ApiRequest('/users').post(user).then((response) => { - var user = response.data; + dispatch({ type: Action.UPDATE_USER, user }); +}; - // Add display fields - parseUser(user); +export const addUser = (user) => async (dispatch) => { + const response = await dispatch(new ApiRequest('/users').post(user)); + let userResponse = response.data; - store.dispatch({ type: Action.ADD_USER, user: user }); + // Add display fields + parseUser(userResponse); - return user; - }); -} + dispatch({ type: Action.ADD_USER, user: userResponse }); -export function updateUser(user) { - return new ApiRequest(`/users/${user.id}`).put(user).then((response) => { - var user = response.data; + return userResponse; +}; - // Add display fields - parseUser(user); +export const updateUser = (user) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/users/${user.id}`).put(user)); + let userResponse = response.data; - store.dispatch({ type: Action.UPDATE_USER, user: user }); + // Add display fields + parseUser(userResponse); - return user; - }); -} + dispatch({ type: Action.UPDATE_USER, user: userResponse }); -export function deleteUser(user) { - return new ApiRequest(`/users/${user.id}/delete`).post().then((response) => { - var user = response.data; + return userResponse; +}; - // Add display fields - parseUser(user); +export const deleteUser = (user) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/users/${user.id}/delete`).post()); + let userResponse = response.data; - store.dispatch({ type: Action.DELETE_USER, user: user }); - }); -} + // Add display fields + parseUser(userResponse); -export function addUserRole(userId, userRole) { - return new ApiRequest(`/users/${userId}/roles`).post(userRole).then(() => { - // After updating the user's role, refresh the user state. - return getUser(userId); - }); -} + dispatch({ type: Action.DELETE_USER, user: userResponse }); +}; -export function updateUserRoles(userId, userRoleArray) { - return new ApiRequest(`/users/${userId}/roles`).put(userRoleArray).then(() => { - // After updating the user's role, refresh the user state. - return getUser(userId); - }); -} +export const addUserRole = (userId, userRole) => async (dispatch) => { + await dispatch(new ApiRequest(`/users/${userId}/roles`).post(userRole)); + // After updating the user's role, refresh the user state. + dispatch(getUser(userId)); +}; -export function getCurrentUserDistricts() { - return new ApiRequest('/userdistricts').get().then((response) => { - store.dispatch({ - type: Action.CURRENT_USER_DISTRICTS, - currentUserDistricts: response.data, - }); - return response; +export const updateUserRoles = (userId, userRoleArray) => async (dispatch) => { + await dispatch(new ApiRequest(`/users/${userId}/roles`).put(userRoleArray)); + // After updating the user's role, refresh the user state. + dispatch(getUser(userId)); +}; + +export const getCurrentUserDistricts = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/userdistricts').get()); + dispatch({ + type: Action.CURRENT_USER_DISTRICTS, + currentUserDistricts: response.data, }); -} + return response; +}; -export function getUserDistricts(userId) { - return new ApiRequest(`/users/${userId}/districts`).get().then((response) => { - store.dispatch({ - type: Action.USER_DISTRICTS, - userDistricts: response.data, - }); - return response; +export const getUserDistricts = (userId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/users/${userId}/districts`).get()); + dispatch({ + type: Action.USER_DISTRICTS, + userDistricts: response.data, }); -} + return response; +}; -export function addUserDistrict(district) { - return new ApiRequest(`/userdistricts`).put(district).then((response) => { - store.dispatch({ - type: Action.USER_DISTRICTS, - userDistricts: response.data, - }); - return response; +export const addUserDistrict = (district) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/userdistricts`).put(district)); + dispatch({ + type: Action.USER_DISTRICTS, + userDistricts: response.data, }); -} + return response; +}; -export function editUserDistrict(district) { - return new ApiRequest(`/userdistricts/${district.id}`).post(district).then((response) => { - store.dispatch({ - type: Action.USER_DISTRICTS, - userDistricts: response.data, - }); - return response; +export const editUserDistrict = (district) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/userdistricts/${district.id}`).post(district)); + dispatch({ + type: Action.USER_DISTRICTS, + userDistricts: response.data, }); -} + return response; +}; -export function deleteUserDistrict(district) { - return new ApiRequest(`/userdistricts/${district.id}/delete`).post().then((response) => { - store.dispatch({ - type: Action.USER_DISTRICTS, - userDistricts: response.data, - }); - return response; +export const deleteUserDistrict = (district) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/userdistricts/${district.id}/delete`).post()); + dispatch({ + type: Action.USER_DISTRICTS, + userDistricts: response.data, }); -} + return response; +}; -export function switchUserDistrict(districtId) { - return new ApiRequest(`/userdistricts/${districtId}/switch`).post(); -} +export const switchUserDistrict = (districtId) => async (dispatch) => { + return await dispatch(new ApiRequest(`/userdistricts/${districtId}/switch`).post()); +}; -export function getSearchSummaryCounts() { - return new ApiRequest('/counts').get().then((response) => { - store.dispatch({ - type: Action.UPDATE_SEARCH_SUMMARY_COUNTS, - searchSummaryCounts: response.data, - }); - return response; +export const getSearchSummaryCounts = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/counts').get()); + dispatch({ + type: Action.UPDATE_SEARCH_SUMMARY_COUNTS, + searchSummaryCounts: response.data, }); -} + return response; +}; //////////////////// // Roles, Permissions //////////////////// -function parseRole(role) { +const parseRole = (role) => { role.path = `${Constant.ROLES_PATHNAME}/${role.id}`; role.url = `${role.path}`; role.historyEntity = History.makeHistoryEntity(Constant.HISTORY_ROLE, role); role.canEdit = true; role.canDelete = false; -} +}; -export function searchRoles(params) { - return new ApiRequest('/roles').get(params).then((response) => { - var roles = normalize(response.data); +export const searchRoles = (params) => async (dispatch) => { + const response = await dispatch(new ApiRequest('/roles').get(params)); + let roles = normalize(response.data); - // Add display fields - _.map(roles, (role) => { - parseRole(role); - }); - - store.dispatch({ type: Action.UPDATE_ROLES, roles: roles }); + // Add display fields + _.map(roles, (role) => { + parseRole(role); }); -} -export function getRole(roleId) { - return new ApiRequest(`/roles/${roleId}`).get().then((response) => { - var role = response.data; + dispatch({ type: Action.UPDATE_ROLES, roles }); +}; - // Add display fields - parseRole(role); +export const getRole = (roleId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/roles/${roleId}`).get()); + let role = response.data; - store.dispatch({ type: Action.UPDATE_ROLE, role: role }); - }); -} + // Add display fields + parseRole(role); -export function addRole(role) { - return new ApiRequest('/roles').post(role).then((response) => { - var role = response.data; + dispatch({ type: Action.UPDATE_ROLE, role }); +}; - // Add display fields - parseRole(role); +export const addRole = (role) => async (dispatch) => { + const response = await dispatch(new ApiRequest('/roles').post(role)); + let roleResponse = response.data; - store.dispatch({ type: Action.ADD_ROLE, role: role }); - }); -} + // Add display fields + parseRole(roleResponse); -export function updateRole(role) { - return new ApiRequest(`/roles/${role.id}`).put(role).then((response) => { - var role = response.data; + dispatch({ type: Action.ADD_ROLE, role: roleResponse }); +}; - // Add display fields - parseRole(role); +export const updateRole = (role) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/roles/${role.id}`).put(role)); + let roleResponse = response.data; - store.dispatch({ type: Action.UPDATE_ROLE, role: role }); - }); -} + // Add display fields + parseRole(roleResponse); -export function deleteRole(role) { - return new ApiRequest(`/roles/${role.id}/delete`).post().then((response) => { - var role = response.data; + dispatch({ type: Action.UPDATE_ROLE, role: roleResponse }); +}; - // Add display fields - parseRole(role); +export const deleteRole = (role) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/roles/${role.id}/delete`).post()); + let roleResponse = response.data; - store.dispatch({ type: Action.DELETE_ROLE, role: role }); - }); -} + // Add display fields + parseRole(roleResponse); -export function getRolePermissions(roleId) { - return new ApiRequest(`/roles/${roleId}/permissions`).get().then((response) => { - var permissions = normalize(response.data); + dispatch({ type: Action.DELETE_ROLE, role: roleResponse }); +}; - store.dispatch({ - type: Action.UPDATE_ROLE_PERMISSIONS, - rolePermissions: permissions, - }); +export const getRolePermissions = (roleId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/roles/${roleId}/permissions`).get()); + dispatch({ + type: Action.UPDATE_ROLE_PERMISSIONS, + rolePermissions: normalize(response.data), }); -} +}; -export function updateRolePermissions(roleId, permissionsArray) { - return new ApiRequest(`/roles/${roleId}/permissions`).put(permissionsArray).then(() => { - // After updating the role's permissions, refresh the permissions state. - return getRolePermissions(roleId); - }); -} +export const updateRolePermissions = (roleId, permissionsArray) => async (dispatch) => { + await dispatch(new ApiRequest(`/roles/${roleId}/permissions`).put(permissionsArray)); + // After updating the role's permissions, refresh the permissions state. + dispatch(getRolePermissions(roleId)); +}; //////////////////// // Favourites //////////////////// -export function getFavourites() { - return new ApiRequest('/users/current/favourites').get().then((response) => { - var favourites = _.chain(response.data) - .groupBy('type') - .mapValues((type) => - _.chain(type) - .values() - .map((object) => [object.id, object]) - .fromPairs() - .value() - ) - .value(); - - store.dispatch({ type: Action.UPDATE_FAVOURITES, favourites: favourites }); - }); -} - -export function addFavourite(favourite) { - return new ApiRequest('/users/current/favourites').post(favourite).then((response) => { - store.dispatch({ type: Action.ADD_FAVOURITE, favourite: response.data }); - }); -} - -export function updateFavourite(favourite) { - return new ApiRequest('/users/current/favourites').put(favourite).then((response) => { - store.dispatch({ - type: Action.UPDATE_FAVOURITE, - favourite: response.data, - }); - }); -} - -export function deleteFavourite(favourite) { - return new ApiRequest(`/users/current/favourites/${favourite.id}/delete`).post().then((response) => { - store.dispatch({ - type: Action.DELETE_FAVOURITE, - favourite: response.data, - }); - }); -} +export const getFavourites = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/users/current/favourites').get()); + const favourites = _.chain(response.data) + .groupBy('type') + .mapValues((type) => + _.chain(type) + .values() + .map((object) => [object.id, object]) + .fromPairs() + .value() + ) + .value(); + + dispatch({ type: Action.UPDATE_FAVOURITES, favourites }); +}; + +export const addFavourite = (favourite) => async (dispatch) => { + const response = await dispatch(new ApiRequest('/users/current/favourites').post(favourite)); + dispatch({ type: Action.ADD_FAVOURITE, favourite: response.data }); +}; + +export const updateFavourite = (favourite) => async (dispatch) => { + const response = await dispatch(new ApiRequest('/users/current/favourites').put(favourite)); + dispatch({ + type: Action.UPDATE_FAVOURITE, + favourite: response.data, + }); +}; + +export const deleteFavourite = (favourite) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/users/current/favourites/${favourite.id}/delete`).post()); + dispatch({ + type: Action.DELETE_FAVOURITE, + favourite: response.data, + }); +}; //////////////////// // Equipment //////////////////// -function getBlockDisplayName(blockNumber, numberOfBlocks, seniority) { +const getBlockDisplayName = (blockNumber, numberOfBlocks, seniority) => { if (blockNumber === numberOfBlocks) { return `Open - ${seniority}`; - } else if (blockNumber === 1) { + } + if (blockNumber === 1) { return `1 - ${seniority}`; - } else if (blockNumber === 2) { + } + if (blockNumber === 2) { return `2 - ${seniority}`; - } else if (seniority != null) { + } + if (seniority != null) { return `Open - ${seniority}`; } return 'Open'; -} +}; -function parseEquipment(equipment) { +const parseEquipment = (equipment) => (dispatch) => { if (!equipment.owner) { equipment.owner = { id: 0, organizationName: '' }; } @@ -464,303 +433,267 @@ function parseEquipment(equipment) { equipment.url = `${equipment.path}`; equipment.name = `code ${equipment.equipmentCode}`; equipment.historyEntity = History.makeHistoryEntity(Constant.HISTORY_EQUIPMENT, equipment); - equipment.documentAdded = Log.equipmentDocumentAdded; - equipment.documentsAdded = Log.equipmentDocumentsAdded; - equipment.documentDeleted = Log.equipmentDocumentDeleted; + equipment.documentAdded = (e, d) => dispatch(Log.equipmentDocumentAdded(e, d)); + equipment.documentsAdded = (e) => dispatch(Log.equipmentDocumentsAdded(e)); + equipment.documentDeleted = (e, d) => dispatch(Log.equipmentDocumentDeleted(e, d)); - equipment.getDocumentsPromise = getEquipmentDocuments; + equipment.getDocumentsPromise = (equipmentId) => dispatch(getEquipmentDocuments(equipmentId)); equipment.uploadDocumentPath = `/equipment/${equipment.id}/attachments`; equipment.canView = true; equipment.canEdit = true; equipment.canDelete = false; // TODO Needs input from Business whether this is needed. -} +}; -function generateSortableEquipmentCode(equipment) { +const generateSortableEquipmentCode = (equipment) => { return equipment.equipmentPrefix && equipment.equipmentNumber ? `${equipment.equipmentPrefix}${_.padStart(equipment.equipmentNumber, 3, '0')}` : equipment.equipmentCode; -} - -export function searchEquipmentList(params) { - store.dispatch({ type: Action.EQUIPMENT_LIST_REQUEST }); - return new ApiRequest('/equipment/search').get(params).then((response) => { - var equipmentList = normalize(response.data); - - _.map(equipmentList, (equipment) => { - equipment.details = [ - equipment.make || '-', - equipment.model || '-', - equipment.size || '-', - equipment.year || '-', - ].join('/'); - equipment.sortableEquipmentCode = generateSortableEquipmentCode(equipment); - }); +}; - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_LIST, - equipmentList: equipmentList, - }); - }); -} +export const searchEquipmentList = (params) => async (dispatch) => { + dispatch({ type: Action.EQUIPMENT_LIST_REQUEST }); + const response = await dispatch(new ApiRequest('/equipment/search').get(params)); + let equipmentList = normalize(response.data); -export function getEquipment(equipmentId) { - return new ApiRequest(`/equipment/${equipmentId}`).get().then((response) => { - var equipment = response.data; + _.map(equipmentList, (equipment) => { + equipment.details = [ + equipment.make || '-', + equipment.model || '-', + equipment.size || '-', + equipment.year || '-', + ].join('/'); + equipment.sortableEquipmentCode = generateSortableEquipmentCode(equipment); + }); + + dispatch({ type: Action.UPDATE_EQUIPMENT_LIST, equipmentList }); +}; + +export const getEquipment = (equipmentId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipment/${equipmentId}`).get()); + let equipment = response.data; + + // Add display fields + dispatch(parseEquipment(equipment)); - // Add display fields - parseEquipment(equipment); + dispatch({ type: Action.UPDATE_EQUIPMENT, equipment }); +}; - store.dispatch({ type: Action.UPDATE_EQUIPMENT, equipment: equipment }); +export const getEquipmentLite = () => async (dispatch, getState) => { + const silent = getState().lookups.equipment.lite.loaded; + const response = await dispatch(new ApiRequest('/equipment/lite', { silent }).get()); + dispatch({ + type: Action.UPDATE_EQUIPMENT_LITE_LOOKUP, + equipment: normalize(response.data), }); -} +}; -export function getEquipmentLite() { - const silent = store.getState().lookups.equipment.lite.loaded; - return new ApiRequest('/equipment/lite', { silent }).get().then((response) => { - var equipment = normalize(response.data); - - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_LITE_LOOKUP, - equipment: equipment, - }); +export const getEquipmentAgreementSummary = () => async (dispatch, getState) => { + const silent = getState().lookups.equipment.ts.loaded; + const response = await dispatch(new ApiRequest('/equipment/agreementSummary', { silent }).get()); + dispatch({ + type: Action.UPDATE_EQUIPMENT_AGREEMENT_SUMMARY_LOOKUP, + equipment: response.data, }); -} +}; -export function getEquipmentAgreementSummary() { - const silent = store.getState().lookups.equipment.ts.loaded; - return new ApiRequest('/equipment/agreementSummary', { silent }).get().then((response) => { - var equipment = normalize(response.data); - - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_AGREEMENT_SUMMARY_LOOKUP, - equipment: equipment, - }); +export const getEquipmentTs = () => async (dispatch, getState) => { + const silent = getState().lookups.equipment.ts.loaded; + const response = await dispatch(new ApiRequest('/equipment/liteTs', { silent }).get()); + dispatch({ + type: Action.UPDATE_EQUIPMENT_TS_LOOKUP, + equipment: normalize(response.data), }); -} - -export function getEquipmentTs() { - const silent = store.getState().lookups.equipment.ts.loaded; - return new ApiRequest('/equipment/liteTs', { silent }).get().then((response) => { - var equipment = normalize(response.data); +}; - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_TS_LOOKUP, - equipment: equipment, - }); +export const getEquipmentHires = () => async (dispatch, getState) => { + const silent = getState().lookups.equipment.hires.loaded; + const response = await dispatch(new ApiRequest('/equipment/liteHires', { silent }).get()); + dispatch({ + type: Action.UPDATE_EQUIPMENT_HIRES_LOOKUP, + equipment: normalize(response.data), }); -} +}; -export function getEquipmentHires() { - const silent = store.getState().lookups.equipment.hires.loaded; - return new ApiRequest('/equipment/liteHires', { silent }).get().then((response) => { - var equipment = normalize(response.data); +export const addEquipment = (equipment) => async (dispatch) => { + const response = await dispatch(new ApiRequest('/equipment').post(equipment)); + let equipmentResponse = response.data; - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_HIRES_LOOKUP, - equipment: equipment, - }); - }); -} + // Add display fields + dispatch(parseEquipment(equipmentResponse)); -export function addEquipment(equipment) { - return new ApiRequest('/equipment').post(equipment).then((response) => { - var equipment = response.data; + dispatch({ type: Action.UPDATE_EQUIPMENT, equipment: equipmentResponse }); + dispatch(getEquipmentLite()); + dispatch(getEquipmentTs()); + dispatch(getEquipmentHires()); - // Add display fields - parseEquipment(equipment); + return equipmentResponse; +}; - store.dispatch({ type: Action.UPDATE_EQUIPMENT, equipment: equipment }); +export const updateEquipment = (equipment) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipment/${equipment.id}`).put(equipment)); + let equipmentResponse = response.data; - getEquipmentLite(); - getEquipmentTs(); - getEquipmentHires(); + // Add display fields + dispatch(parseEquipment(equipmentResponse)); - return equipment; - }); -} + dispatch({ type: Action.UPDATE_EQUIPMENT, equipment: equipmentResponse }); + dispatch(getEquipmentLite()); + dispatch(getEquipmentTs()); + dispatch(getEquipmentHires()); +}; -export function updateEquipment(equipment) { - return new ApiRequest(`/equipment/${equipment.id}`).put(equipment).then((response) => { - var equipment = response.data; +export const verifyEquipmentActive = (id) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipment/${id}/verifyactive`).put(id)); + let equipment = response.data; - // Add display fields - parseEquipment(equipment); + // Add display fields + dispatch(parseEquipment(equipment)); - store.dispatch({ type: Action.UPDATE_EQUIPMENT, equipment: equipment }); + dispatch({ type: Action.UPDATE_EQUIPMENT, equipment }); + dispatch(getEquipmentLite()); + dispatch(getEquipmentTs()); + dispatch(getEquipmentHires()); +}; - getEquipmentLite(); - getEquipmentTs(); - getEquipmentHires(); +export const addEquipmentHistory = (equipmentId, history) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipment/${equipmentId}/history`).post(history)); + let historyResponse = normalize(response.data); + // Add display fields + _.map(historyResponse, (h) => { + parseHistory(h); }); -} - -export function verifyEquipmentActive(id) { - return new ApiRequest(`/equipment/${id}/verifyactive`).put(id).then((response) => { - var equipment = response.data; - - // Add display fields - parseEquipment(equipment); - - store.dispatch({ type: Action.UPDATE_EQUIPMENT, equipment: equipment }); - getEquipmentLite(); - getEquipmentTs(); - getEquipmentHires(); + dispatch({ + type: Action.UPDATE_EQUIPMENT_HISTORY, + history: historyResponse, + id: equipmentId, }); -} +}; -export function addEquipmentHistory(equipmentId, history) { - return new ApiRequest(`/equipment/${equipmentId}/history`).post(history).then((response) => { - var history = normalize(response.data); - // Add display fields - _.map(history, (history) => { - parseHistory(history); - }); +export const getEquipmentHistory = (equipmentId, params) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipment/${equipmentId}/history`).get(params)); + let history = normalize(response.data); - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_HISTORY, - history, - id: equipmentId, - }); + // Add display fields + _.map(history, (h) => { + parseHistory(h); }); -} - -export function getEquipmentHistory(equipmentId, params) { - return new ApiRequest(`/equipment/${equipmentId}/history`).get(params).then((response) => { - var history = normalize(response.data); - // Add display fields - _.map(history, (history) => { - parseHistory(history); - }); - - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_HISTORY, - history, - id: equipmentId, - }); + dispatch({ + type: Action.UPDATE_EQUIPMENT_HISTORY, + history, + id: equipmentId, }); -} +}; -export function getEquipmentDocuments(equipmentId) { - return new ApiRequest(`/equipment/${equipmentId}/attachments`).get().then((response) => { - var documents = normalize(response.data); +export const getEquipmentDocuments = (equipmentId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipment/${equipmentId}/attachments`).get()); + let documents = normalize(response.data); - // Add display fields - _.map(documents, (document) => { - parseDocument(document); - }); - - store.dispatch({ type: Action.UPDATE_DOCUMENTS, documents: documents }); + // Add display fields + _.map(documents, (document) => { + parseDocument(document); }); -} -// XXX: Looks like this is unused -// export function addEquipmentDocument(equipmentId, files) { -// return new ApiRequest(`/equipment/${ equipmentId }/attachments`).post(files); -// } - -export function getEquipmentNotes(equipmentId) { - return new ApiRequest(`/equipment/${equipmentId}/notes`).get().then((response) => { - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_NOTES, - notes: response.data, - }); - return response.data; - }); -} + dispatch({ type: Action.UPDATE_DOCUMENTS, documents }); +}; -export function addEquipmentNote(equipmentId, note) { - return new ApiRequest(`/equipment/${equipmentId}/note`).post(note).then((response) => { - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_NOTES, - notes: response.data, - }); - return response.data; - }); -} - -export function equipmentDuplicateCheck(id, serialNumber) { - return new ApiRequest(`/equipment/${id}/duplicates/${serialNumber}`).get(); -} - -export function changeEquipmentStatus(status) { - return new ApiRequest(`/equipment/${status.id}/status`).put(status).then((response) => { - var equipment = response.data; - // Add display fields - parseEquipment(equipment); - store.dispatch({ type: Action.UPDATE_EQUIPMENT, equipment: equipment }); - return response; - }); -} - -export function getEquipmentRentalAgreements(equipmentId) { - return new ApiRequest(`/equipment/${equipmentId}/rentalAgreements`).get().then((response) => { - var rentalAgreements = normalize(response.data); - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_RENTAL_AGREEMENTS, - rentalAgreements: rentalAgreements, - }); - return rentalAgreements; - }); -} - -export function cloneEquipmentRentalAgreement(data) { - return new ApiRequest(`/equipment/${data.equipmentId}/rentalAgreementClone`).post(data).then((response) => { - var agreement = response.data; - // Add display fields - parseRentalAgreement(agreement); - store.dispatch({ - type: Action.UPDATE_RENTAL_AGREEMENT, - rentalAgreement: agreement, - }); - return response; +// XXX: Looks like this is unused +// export const addEquipmentDocument = (equipmentId, files) => async (dispatch) => { +// return await dispatch(new ApiRequest(`/equipment/${ equipmentId }/attachments`).post(files)); +// }; + +export const getEquipmentNotes = (equipmentId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipment/${equipmentId}/notes`).get()); + dispatch({ + type: Action.UPDATE_EQUIPMENT_NOTES, + notes: response.data, + }); + return response.data; +}; + +export const addEquipmentNote = (equipmentId, note) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipment/${equipmentId}/note`).post(note)); + dispatch({ + type: Action.UPDATE_EQUIPMENT_NOTES, + notes: response.data, + }); + return response.data; +}; + +export const equipmentDuplicateCheck = (id, serialNumber) => async (dispatch) => { + return await dispatch(new ApiRequest(`/equipment/${id}/duplicates/${serialNumber}`).get()); +}; + +export const changeEquipmentStatus = (status) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipment/${status.id}/status`).put(status)); + let equipment = response.data; + // Add display fields + dispatch(parseEquipment(equipment)); + dispatch({ type: Action.UPDATE_EQUIPMENT, equipment }); + return response; +}; + +export const getEquipmentRentalAgreements = (equipmentId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipment/${equipmentId}/rentalAgreements`).get()); + const rentalAgreements = normalize(response.data); + dispatch({ + type: Action.UPDATE_EQUIPMENT_RENTAL_AGREEMENTS, + rentalAgreements, + }); + return rentalAgreements; +}; + +export const cloneEquipmentRentalAgreement = (data) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipment/${data.equipmentId}/rentalAgreementClone`).post(data)); + let agreement = response.data; + // Add display fields + parseRentalAgreement(agreement); + dispatch({ + type: Action.UPDATE_RENTAL_AGREEMENT, + rentalAgreement: agreement, }); -} + return response; +}; -export function equipmentSeniorityListDoc(localAreas, types, counterCopy) { - var params = { localareas: localAreas, types: types }; +export const equipmentSeniorityListDoc = (localAreas, types, counterCopy) => async (dispatch) => { + const params = { localareas: localAreas, types: types }; if (counterCopy) { params.counterCopy = counterCopy; } - return new ApiRequest('/equipment/seniorityListDoc') - .get(params, { responseType: Constant.RESPONSE_TYPE_BLOB }) - .then((response) => { - return response; - }); -} + return await dispatch(new ApiRequest('/equipment/seniorityListDoc') + .get(params, { responseType: Constant.RESPONSE_TYPE_BLOB })); +}; //////////////////// // Physical Attachments //////////////////// // Introduce later -// function parsePhysicalAttachment(attachment) { +// const parsePhysicalAttachment = (attachment) => { // if (!attachment.type) { attachment.type = { id: 0, code: '', description: ''}; } // attachment.typeName = attachment.type.description; // // TODO Add grace period logic to editing/deleting attachments // attachment.canEdit = true; // attachment.canDelete = true; -// } +// }; // XXX: Looks like this is unused -// export function getPhysicalAttachment(id) { -// return new ApiRequest(`/equipment/${id}/equipmentAttachments`).get().then(response => { -// store.dispatch({ type: Action.UPDATE_EQUIPMENT_ATTACHMENTS, physicalAttachments: response.data }); -// }); -// } +// export const getPhysicalAttachment = (id) => async (dispatch) => { +// const response = await dispatch(new ApiRequest(`/equipment/${id}/equipmentAttachments`).get()); +// dispatch({ type: Action.UPDATE_EQUIPMENT_ATTACHMENTS, physicalAttachments: response.data }); +// }; // XXX: Looks like this is unused -// export function addPhysicalAttachment(attachment) { -// return new ApiRequest('/equipmentAttachments').post(attachment).then(response => { -// store.dispatch({ type: Action.ADD_EQUIPMENT_ATTACHMENT, physicalAttachment: response.data }); -// }); -// } +// export const addPhysicalAttachment = (attachment) => async (dispatch) => { +// const response = await dispatch(new ApiRequest('/equipmentAttachments').post(attachment)); +// dispatch({ type: Action.ADD_EQUIPMENT_ATTACHMENT, physicalAttachment: response.data }); +// }; -export function addPhysicalAttachments(equipmentId, attachmentTypeNames) { +export const addPhysicalAttachments = (equipmentId, attachmentTypeNames) => async (dispatch) => { const attachments = attachmentTypeNames.map((typeName) => { // "concurrencyControlNumber": 0, return { @@ -771,37 +704,34 @@ export function addPhysicalAttachments(equipmentId, attachmentTypeNames) { }; }); - return new ApiRequest('/equipmentAttachments/bulk').post(attachments).then((response) => { - store.dispatch({ - type: Action.ADD_EQUIPMENT_ATTACHMENTS, - physicalAttachments: response.data, - }); + const response = await dispatch(new ApiRequest('/equipmentAttachments/bulk').post(attachments)); + dispatch({ + type: Action.ADD_EQUIPMENT_ATTACHMENTS, + physicalAttachments: response.data, }); -} +}; -export function updatePhysicalAttachment(attachment) { - return new ApiRequest(`/equipmentAttachments/${attachment.id}`).put(attachment).then((response) => { - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_ATTACHMENT, - physicalAttachment: response.data, - }); +export const updatePhysicalAttachment = (attachment) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipmentAttachments/${attachment.id}`).put(attachment)); + dispatch({ + type: Action.UPDATE_EQUIPMENT_ATTACHMENT, + physicalAttachment: response.data, }); -} +}; -export function deletePhysicalAttachment(attachmentId) { - return new ApiRequest(`/equipmentAttachments/${attachmentId}/delete`).post().then((response) => { - store.dispatch({ - type: Action.DELETE_EQUIPMENT_ATTACHMENT, - physicalAttachment: response.data, - }); +export const deletePhysicalAttachment = (attachmentId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/equipmentAttachments/${attachmentId}/delete`).post()); + dispatch({ + type: Action.DELETE_EQUIPMENT_ATTACHMENT, + physicalAttachment: response.data, }); -} +}; //////////////////// // Owners //////////////////// -function parseOwner(owner) { +const parseOwner = (owner) => (dispatch) => { // Rename properties owner.equipmentList = owner.equipment; delete owner.equipment; @@ -857,9 +787,9 @@ function parseOwner(owner) { owner.url = `${owner.path}`; owner.name = owner.organizationName; owner.historyEntity = History.makeHistoryEntity(Constant.HISTORY_OWNER, owner); - owner.documentAdded = Log.ownerDocumentAdded; - owner.documentsAdded = Log.ownerDocumentsAdded; - owner.documentDeleted = Log.ownerDocumentDeleted; + owner.documentAdded = (o, d) => dispatch(Log.ownerDocumentAdded(o, d)); + owner.documentsAdded = (o) => dispatch(Log.ownerDocumentsAdded(o)); + owner.documentDeleted = (o, d) => dispatch(Log.ownerDocumentDeleted(o, d)); // Add display fields for owner contacts owner.contacts = owner.contacts.map((contact) => parseContact(contact, owner)); @@ -868,7 +798,7 @@ function parseOwner(owner) { parseDocument(document); }); _.map(owner.equipmentList, (equipment) => { - parseEquipment(equipment); + dispatch(parseEquipment(equipment)); }); // TODO Owner status needs to be populated in sample data. Setting to Approved for the time being... @@ -885,254 +815,239 @@ function parseOwner(owner) { owner.numberOfEquipment = Object.keys(owner.equipmentList).length; owner.numberOfPolicyDocuments = owner.numberOfPolicyDocuments || 0; // TODO - owner.getDocumentsPromise = getOwnerDocuments; + owner.getDocumentsPromise = (ownerId) => dispatch(getOwnerDocuments(ownerId)); owner.uploadDocumentPath = `/owners/${owner.id}/attachments`; owner.canView = true; owner.canEdit = true; owner.canDelete = false; // TODO Needs input from Business whether this is needed. -} +}; -export function searchOwners(params) { - store.dispatch({ type: Action.OWNERS_REQUEST }); - return new ApiRequest('/owners/search').get(params).then((response) => { - var owners = normalize(response.data); - store.dispatch({ type: Action.UPDATE_OWNERS, owners: owners }); - }); -} +export const searchOwners = (params) => async (dispatch) => { + dispatch({ type: Action.OWNERS_REQUEST }); + const response = await dispatch(new ApiRequest('/owners/search').get(params)); + dispatch({ type: Action.UPDATE_OWNERS, owners: normalize(response.data) }); +}; -export function getOwner(ownerId) { - return new ApiRequest(`/owners/${ownerId}`).get().then((response) => { - var owner = response.data; +export const getOwner = (ownerId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/owners/${ownerId}`).get()); + let owner = response.data; - // Add display fields - parseOwner(owner); + // Add display fields + dispatch(parseOwner(owner)); - store.dispatch({ type: Action.UPDATE_OWNER, owner }); + dispatch({ type: Action.UPDATE_OWNER, owner }); - return owner; - }); -} + return owner; +}; -export function addOwner(owner) { - return new ApiRequest('/owners').post(owner).then((response) => { - var owner = response.data; +export const addOwner = (owner) => async (dispatch) => { + const response = await dispatch(new ApiRequest('/owners').post(owner)); + let ownerResponse = response.data; - // Add display fields - parseOwner(owner); + // Add display fields + dispatch(parseOwner(ownerResponse)); - store.dispatch({ type: Action.ADD_OWNER, owner }); + dispatch({ type: Action.ADD_OWNER, owner: ownerResponse }); - return owner; - }); -} + return ownerResponse; +}; -export function updateOwner(owner) { - store.dispatch({ type: Action.UPDATE_OWNER, owner }); +export const updateOwner = (owner) => async (dispatch) => { + dispatch({ type: Action.UPDATE_OWNER, owner }); // Omit `contacts` to ensure that the existing contacts don't mess up the PUT call - return new ApiRequest(`/owners/${owner.id}`).put(_.omit(owner, 'contacts')).then((response) => { - var owner = response.data; + const response = await dispatch(new ApiRequest(`/owners/${owner.id}`).put(_.omit(owner, 'contacts'))); + let ownerResponse = response.data; - // Add display fields - parseOwner(owner); + // Add display fields + dispatch(parseOwner(ownerResponse)); - store.dispatch({ type: Action.UPDATE_OWNER, owner }); - }); -} + dispatch({ type: Action.UPDATE_OWNER, owner: ownerResponse }); +}; // XXX: Looks like this is unused -// export function deleteOwner(owner) { -// return new ApiRequest(`/owners/${ owner.id }/delete`).post().then(response => { -// var owner = response.data; +// export const deleteOwner = (owner) => async (dispatch) => { +// const response = await dispatch(new ApiRequest(`/owners/${ owner.id }/delete`).post()); +// let ownerResponse = response.data; -// // Add display fields -// parseOwner(owner); +// // Add display fields +// dispatch(parseOwner(ownerResponse)); -// store.dispatch({ type: Action.DELETE_OWNER, owner }); -// }); -// } +// dispatch({ type: Action.DELETE_OWNER, owner: ownerResponse }); +// }; -export function saveOwnerContact(owner, contact) { +export const saveOwnerContact = (owner, contact) => async (dispatch) => { const isNew = contact.id === 0; if (!isNew) { // don't update if this is a new contact - add after post() completes - store.dispatch({ + dispatch({ type: Action.UPDATE_OWNER_CONTACT, ownerId: owner.id, contact, }); } - return new ApiRequest(`/owners/${owner.id}/contacts/${contact.isPrimary}`).post(contact).then((response) => { - var updatedContact = response.data; - - // Add display fields - parseContact(updatedContact, owner); // owner's primary contact could be outdated - updatedContact.isPrimary = contact.isPrimary; - - if (isNew) { - // add newly created contact to Redux store's contacts - store.dispatch({ - type: Action.ADD_OWNER_CONTACT, - ownerId: owner.id, - contact: updatedContact, - }); - } else { - // Update Redux store's data with the server's data - store.dispatch({ - type: Action.UPDATE_OWNER_CONTACT, - ownerId: owner.id, - contact: updatedContact, - }); - } - - return updatedContact; - }); -} - -export function addOwnerHistory(ownerId, history) { - return new ApiRequest(`/owners/${ownerId}/history`).post(history).then((response) => { - var history = normalize(response.data); - // Add display fields - _.map(history, (history) => { - parseHistory(history); - }); + const response = await dispatch(new ApiRequest(`/owners/${owner.id}/contacts/${contact.isPrimary}`).post(contact)); + let updatedContact = response.data; + + // Add display fields + parseContact(updatedContact, owner); // owner's primary contact could be outdated + updatedContact.isPrimary = contact.isPrimary; - store.dispatch({ - type: Action.UPDATE_OWNER_HISTORY, - history, - id: ownerId, + if (isNew) { + // add newly created contact to Redux store's contacts + dispatch({ + type: Action.ADD_OWNER_CONTACT, + ownerId: owner.id, + contact: updatedContact, }); + } else { + // Update Redux store's data with the server's data + dispatch({ + type: Action.UPDATE_OWNER_CONTACT, + ownerId: owner.id, + contact: updatedContact, + }); + } + + return updatedContact; +}; + +export const addOwnerHistory = (ownerId, history) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/owners/${ownerId}/history`).post(history)); + let historyResponse = normalize(response.data); + // Add display fields + _.map(historyResponse, (h) => { + parseHistory(h); }); -} -export function getOwnerHistory(ownerId, params) { - return new ApiRequest(`/owners/${ownerId}/history`).get(params).then((response) => { - var history = normalize(response.data); - // Add display fields - _.map(history, (history) => { - parseHistory(history); - }); + dispatch({ + type: Action.UPDATE_OWNER_HISTORY, + history: historyResponse, + id: ownerId, + }); +}; - store.dispatch({ - type: Action.UPDATE_OWNER_HISTORY, - history, - id: ownerId, - }); +export const getOwnerHistory = (ownerId, params) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/owners/${ownerId}/history`).get(params)); + let history = normalize(response.data); + // Add display fields + _.map(history, (h) => { + parseHistory(h); }); -} -export function getOwnerDocuments(ownerId) { - return new ApiRequest(`/owners/${ownerId}/attachments`).get().then((response) => { - var documents = normalize(response.data); + dispatch({ + type: Action.UPDATE_OWNER_HISTORY, + history, + id: ownerId, + }); +}; - // Add display fields - _.map(documents, (document) => { - parseDocument(document); - }); +export const getOwnerDocuments = (ownerId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/owners/${ownerId}/attachments`).get()); + let documents = normalize(response.data); - store.dispatch({ type: Action.UPDATE_DOCUMENTS, documents: documents }); + // Add display fields + _.map(documents, (document) => { + parseDocument(document); }); -} + + dispatch({ type: Action.UPDATE_DOCUMENTS, documents }); +}; // XXX: Looks like this is unused -// export function addOwnerDocument(ownerId, files) { -// return new ApiRequest(`/owners/${ ownerId }/attachments`).post(files); -// } - -export function getOwnerEquipment(ownerId) { - return new ApiRequest(`/owners/${ownerId}/equipment`).get().then((response) => { - var equipmentList = normalize(response.data); - - _.map(equipmentList, (equipment) => { - equipment.details = [ - equipment.make || '-', - equipment.model || '-', - equipment.size || '-', - equipment.year || '-', - ].join('/'); - }); +// export const addOwnerDocument = (ownerId, files) => async (dispatch) => { +// return await dispatch(new ApiRequest(`/owners/${ ownerId }/attachments`).post(files)); +// }; - store.dispatch({ - type: Action.UPDATE_OWNER_EQUIPMENT, - equipment: equipmentList, - }); - }); -} +export const getOwnerEquipment = (ownerId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/owners/${ownerId}/equipment`).get()); + let equipmentList = normalize(response.data); -export function updateOwnerEquipment(owner, equipmentArray) { - return new ApiRequest(`/owners/${owner.id}/equipment`).put(equipmentArray); -} + _.map(equipmentList, (equipment) => { + equipment.details = [ + equipment.make || '-', + equipment.model || '-', + equipment.size || '-', + equipment.year || '-', + ].join('/'); + }); -export function getOwnerNotes(ownerId) { - return new ApiRequest(`/owners/${ownerId}/notes`).get().then((response) => { - store.dispatch({ - type: Action.UPDATE_OWNER_NOTES, - ownerId, - notes: response.data, - }); - return response.data; + dispatch({ + type: Action.UPDATE_OWNER_EQUIPMENT, + equipment: equipmentList, }); -} +}; + +export const updateOwnerEquipment = (owner, equipmentArray) => async (dispatch) => { + return await dispatch(new ApiRequest(`/owners/${owner.id}/equipment`).put(equipmentArray)); +}; -export function addOwnerNote(ownerId, note) { - store.dispatch({ type: Action.ADD_OWNER_NOTE, ownerId, note }); - return new ApiRequest(`/owners/${ownerId}/note`).post(note).then((response) => { - return response.data; +export const getOwnerNotes = (ownerId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/owners/${ownerId}/notes`).get()); + dispatch({ + type: Action.UPDATE_OWNER_NOTES, + ownerId, + notes: response.data, }); -} + return response.data; +}; + +export const addOwnerNote = (ownerId, note) => async (dispatch) => { + dispatch({ type: Action.ADD_OWNER_NOTE, ownerId, note }); + const response = await dispatch(new ApiRequest(`/owners/${ownerId}/note`).post(note)); + return response.data; +}; // XXX: Looks like this is unused -// export function getOwnersByDistrict(districtId) { -// return new ApiRequest(`/districts/${districtId}/owners`).get().then((response) => { -// var owners = normalize(response.data); -// // Add display fields -// _.map(owners, owner => { parseOwner(owner); }); -// store.dispatch({ type: Action.UPDATE_OWNERS_LOOKUP, owners: owners }); -// }); -// } - -export function changeOwnerStatus(status) { - return new ApiRequest(`/owners/${status.id}/status`).put(status).then((response) => { - var owner = response.data; - // Add display fields - parseOwner(owner); - store.dispatch({ type: Action.UPDATE_OWNER, owner: owner }); - return response; - }); -} - -export function getStatusLettersDoc(params) { - return new ApiRequest('/owners/verificationDoc').post(params, { +// export const getOwnersByDistrict = (districtId) => async (dispatch) => { +// const response = await dispatch(new ApiRequest(`/districts/${districtId}/owners`).get()); +// let owners = normalize(response.data); +// // Add display fields +// _.map(owners, owner => { dispatch(parseOwner(owner)); }); +// dispatch({ type: Action.UPDATE_OWNERS_LOOKUP, owners }); +// }; + +export const changeOwnerStatus = (status) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/owners/${status.id}/status`).put(status)); + let owner = response.data; + // Add display fields + dispatch(parseOwner(owner)); + dispatch({ type: Action.UPDATE_OWNER, owner }); + return response; +}; + +export const getStatusLettersDoc = (params) => async (dispatch) => { + return await dispatch(new ApiRequest('/owners/verificationDoc').post(params, { responseType: Constant.RESPONSE_TYPE_BLOB, - }); -} + })); +}; -export function getMailingLabelsDoc(params) { - return new ApiRequest('/owners/mailingLabelsDoc').post(params, { +export const getMailingLabelsDoc = (params) => async (dispatch) => { + return await dispatch(new ApiRequest('/owners/mailingLabelsDoc').post(params, { responseType: Constant.RESPONSE_TYPE_BLOB, - }); -} + })); +}; -export function transferEquipment(donorOwnerId, recipientOwnerId, equipment, includeSeniority) { - return new ApiRequest(`/owners/${donorOwnerId}/equipmentTransfer/${recipientOwnerId}/${includeSeniority}`) - .post(equipment) - .then((response) => { - getEquipmentLite(); - getEquipmentTs(); - getEquipmentHires(); +export const transferEquipment = (donorOwnerId, recipientOwnerId, equipment, includeSeniority) => async (dispatch) => { + const response = await dispatch( + new ApiRequest(`/owners/${donorOwnerId}/equipmentTransfer/${recipientOwnerId}/${includeSeniority}`) + .post(equipment)); + + dispatch(getEquipmentLite()); + dispatch(getEquipmentTs()); + dispatch(getEquipmentHires()); - return response; - }); -} + return response; +}; //////////////////// // Contacts //////////////////// -function parseContact(contact, parent) { +const parseContact = (contact, parent) => { contact.name = firstLastName(contact.givenName, contact.surname); contact.phone = contact.workPhoneNumber ? `${contact.workPhoneNumber} (w)` @@ -1140,8 +1055,8 @@ function parseContact(contact, parent) { ? `${contact.mobilePhoneNumber} (c)` : ''; - var parentPath = ''; - var primaryContactId = 0; + let parentPath = ''; + let primaryContactId = 0; if (parent) { parentPath = parent.path || ''; primaryContactId = parent.primaryContact ? parent.primaryContact.id : 0; @@ -1157,79 +1072,74 @@ function parseContact(contact, parent) { contact.canDelete = true; return contact; -} +}; // XXX: Looks like this is unused -// export function getContacts() { -// return new ApiRequest('/contacts').get().then(response => { -// var contacts = normalize(response.data); +// export const getContacts = () => async (dispatch) => { +// const response = await dispatch(new ApiRequest('/contacts').get()); +// let contacts = normalize(response.data); -// // Add display fields -// _.map(contacts, contact => { parseContact(contact); }); +// // Add display fields +// _.map(contacts, contact => { parseContact(contact); }); -// store.dispatch({ type: Action.UPDATE_CONTACTS, contacts: contacts }); -// }); -// } +// dispatch({ type: Action.UPDATE_CONTACTS, contacts }); +// }; // XXX: Looks like this is unused -// export function getContact(contactId) { -// return new ApiRequest(`/contacts/${ contactId }`).get().then(response => { -// var contact = response.data; +// export const getContact = (contactId) => async (dispatch) => { +// const response = await dispatch(new ApiRequest(`/contacts/${ contactId }`).get()); +// let contact = response.data; -// // Add display fields -// parseContact(contact); +// // Add display fields +// parseContact(contact); -// store.dispatch({ type: Action.UPDATE_CONTACT, contact: contact }); -// }); -// } +// dispatch({ type: Action.UPDATE_CONTACT, contact }); +// }; // XXX: Looks like this is unused -// export function addContact(parent, contact) { -// return new ApiRequest('/contacts').post(contact).then(response => { -// var contact = response.data; +// export const addContact = (parent, contact) => async (dispatch) => { +// const response = await dispatch(new ApiRequest('/contacts').post(contact)); +// let contact = response.data; -// // Add display fields -// parseContact(contact, parent); +// // Add display fields +// parseContact(contact, parent); -// store.dispatch({ type: Action.ADD_CONTACT, contact: contact }); -// }); -// } +// dispatch({ type: Action.ADD_CONTACT, contact }); +// }; -// export function updateContact(parent, contact) { -// return new ApiRequest(`/contacts/${ contact.id }`).put(contact).then(response => { -// var contact = response.data; +// export const updateContact = (parent, contact) => async (dispatch) => { +// const response = await dispatch(new ApiRequest(`/contacts/${ contact.id }`).put(contact)); +// let contact = response.data; -// // Add display fields -// parseContact(contact, parent); +// // Add display fields +// parseContact(contact, parent); -// store.dispatch({ type: Action.UPDATE_CONTACT, contact: contact }); -// }); -// } +// dispatch({ type: Action.UPDATE_CONTACT, contact }); +// }; -export function deleteContact(contact) { - store.dispatch({ type: Action.DELETE_CONTACT, contact }); - return new ApiRequest(`/contacts/${contact.id}/delete`).post().then((response) => { - var contact = response.data; +export const deleteContact = (contact) => async (dispatch) => { + dispatch({ type: Action.DELETE_CONTACT, contact }); + const response = await dispatch(new ApiRequest(`/contacts/${contact.id}/delete`).post()); + let contactResponse = response.data; - // Add display fields - parseContact(contact); + // Add display fields + parseContact(contactResponse); - store.dispatch({ type: Action.DELETE_CONTACT, contact }); - }); -} + dispatch({ type: Action.DELETE_CONTACT, contact: contactResponse }); +}; //////////////////// // Documents //////////////////// -function getFileSizeString(fileSizeInBytes) { - var bytes = parseInt(fileSizeInBytes, 10) || 0; - var kbytes = bytes >= 1024 ? bytes / 1024 : 0; - var mbytes = kbytes >= 1024 ? kbytes / 1024 : 0; - var gbytes = mbytes >= 1024 ? mbytes / 1024 : 0; +const getFileSizeString = (fileSizeInBytes) => { + const bytes = parseInt(fileSizeInBytes, 10) || 0; + const kbytes = bytes >= 1024 ? bytes / 1024 : 0; + const mbytes = kbytes >= 1024 ? kbytes / 1024 : 0; + const gbytes = mbytes >= 1024 ? mbytes / 1024 : 0; - var ceiling10 = function (num) { - var adjusted = Math.ceil(num * 10) / 10; + const ceiling10 = (num) => { + const adjusted = Math.ceil(num * 10) / 10; return adjusted.toFixed(1); }; @@ -1240,44 +1150,44 @@ function getFileSizeString(fileSizeInBytes) { : kbytes ? `${Math.ceil(kbytes)} KB` : `${bytes} bytes`; -} +}; -function parseDocument(document) { +const parseDocument = (document) => { document.fileSizeDisplay = getFileSizeString(document.fileSize); document.timestampSort = sortableDateTime(document.lastUpdateTimestamp); document.name = document.fileName; document.canDelete = true; document.historyEntity = History.makeHistoryEntity(Constant.HISTORY_DOCUMENT, document); -} +}; -export function deleteDocument(document) { - return new ApiRequest(`/attachments/${document.id}/delete`).post(); -} +export const deleteDocument = (document) => async (dispatch) => { + return await dispatch(new ApiRequest(`/attachments/${document.id}/delete`).post()); +}; -export function getDownloadDocument(document) { - return new ApiRequest(`/attachments/${document.id}/download`); -} +export const getDownloadDocument = (document) => async (dispatch) => { + return await dispatch(new ApiRequest(`/attachments/${document.id}/download`).getBlob()); +}; -export function getDownloadDocumentURL(document) { +export const getDownloadDocumentURL = (document) => { //XXX: Not used in the application. Last checked 17 Jun 2021. // Not an API call, per se, as it must be called from the browser window. return `${window.location.origin}${window.location.pathname}api/attachments/${document.id}/download`; -} +}; //////////////////// // History //////////////////// -function parseHistory(history) { +const parseHistory = (history) => { history.timestampSort = sortableDateTime(history.lastUpdateTimestamp); -} +}; //////////////////// // Projects //////////////////// -function parseProject(project) { +const parseProject = (project) => (dispatch) => { if (!project.district) { project.district = { id: 0, name: '' }; } @@ -1301,16 +1211,16 @@ function parseProject(project) { project.path = `${Constant.PROJECTS_PATHNAME}/${project.id}`; project.url = `${project.path}`; project.historyEntity = History.makeHistoryEntity(Constant.HISTORY_PROJECT, project); - project.documentAdded = Log.projectDocumentAdded; - project.documentsAdded = Log.projectDocumentsAdded; - project.documentDeleted = Log.projectDocumentDeleted; + project.documentAdded = (p, d) => dispatch(Log.projectDocumentAdded(p, d)); + project.documentsAdded = (p) => dispatch(Log.projectDocumentsAdded(p)); + project.documentDeleted = (p, d) => dispatch(Log.projectDocumentDeleted(p, d)); // Add display fields for contacts project.contacts = project.contacts.map((contact) => parseContact(contact, project)); // Add display fields for rental requests and rental agreements _.map(project.rentalRequests, (obj) => { - parseRentalRequest(obj); + dispatch(parseRentalRequest(obj)); }); _.map(project.rentalAgreements, (obj) => { parseRentalAgreement(obj); @@ -1334,15 +1244,15 @@ function parseProject(project) { ? project.primaryContact.workPhoneNumber || project.primaryContact.mobilePhoneNumber || '' : ''; - project.getDocumentsPromise = getProjectDocuments; + project.getDocumentsPromise = (projectId) => dispatch(getProjectDocuments(projectId)); project.uploadDocumentPath = `/projects/${project.id}/attachments`; project.canView = true; project.canEdit = true; project.canDelete = false; // TODO Needs input from Business whether this is needed. -} +}; -function formatTimeRecords(timeRecords, rentalRequestId) { +const formatTimeRecords = (timeRecords, rentalRequestId) => { let formattedTimeRecords = Object.keys(timeRecords).map((key) => { let timeRecord = {}; timeRecord.workedDate = timeRecords[key].date; @@ -1352,154 +1262,141 @@ function formatTimeRecords(timeRecords, rentalRequestId) { return timeRecord; }); return formattedTimeRecords; -} +}; -export function searchProjects(params) { - store.dispatch({ type: Action.PROJECTS_REQUEST }); - return new ApiRequest('/projects/search').get(params).then((response) => { - var projects = normalize(response.data); +export const searchProjects = (params) => async (dispatch) => { + dispatch({ type: Action.PROJECTS_REQUEST }); + const response = await dispatch(new ApiRequest('/projects/search').get(params)); + let projects = normalize(response.data); - // Add display fields - _.map(projects, (project) => { - parseProject(project); - }); - - store.dispatch({ type: Action.UPDATE_PROJECTS, projects: projects }); + // Add display fields + _.map(projects, (project) => { + dispatch(parseProject(project)); }); -} -export function searchTimeEntries(params) { - store.dispatch({ type: Action.TIME_ENTRIES_REQUEST }); - return new ApiRequest('/timeRecords/search').get(params).then((response) => { - var timeEntries = normalize(response.data); + dispatch({ type: Action.UPDATE_PROJECTS, projects }); +}; - _.map(timeEntries, (entry) => { - entry.localAreaLabel = `${entry.serviceAreaId} - ${entry.localAreaName}`; - entry.equipmentDetails = [entry.make || '-', entry.model || '-', entry.size || '-', entry.year || '-'].join('/'); - entry.sortableEquipmentCode = generateSortableEquipmentCode(entry); - }); +export const searchTimeEntries = (params) => async (dispatch) => { + dispatch({ type: Action.TIME_ENTRIES_REQUEST }); + const response = await dispatch(new ApiRequest('/timeRecords/search').get(params)); + let timeEntries = normalize(response.data); - store.dispatch({ - type: Action.UPDATE_TIME_ENTRIES, - timeEntries: timeEntries, - }); + _.map(timeEntries, (entry) => { + entry.localAreaLabel = `${entry.serviceAreaId} - ${entry.localAreaName}`; + entry.equipmentDetails = [entry.make || '-', entry.model || '-', entry.size || '-', entry.year || '-'].join('/'); + entry.sortableEquipmentCode = generateSortableEquipmentCode(entry); }); -} - -export function searchHiringReport(params) { - store.dispatch({ type: Action.HIRING_RESPONSES_REQUEST }); - return new ApiRequest('/rentalRequests/hireReport').get(params).then((response) => { - var hiringResponses = normalize(response.data); - - _.map(hiringResponses, (entry) => { - entry.localAreaLabel = `${entry.serviceAreaId} - ${entry.localAreaName}`; - entry.equipmentDetails = [ - entry.equipmentMake || '-', - entry.equipmentModel || '-', - entry.equipmentSize || '-', - entry.equipmentYear || '-', - ].join('/'); - entry.sortableEquipmentCode = generateSortableEquipmentCode(entry); - }); - store.dispatch({ - type: Action.UPDATE_HIRING_RESPONSES, - hiringResponses: hiringResponses, - }); + dispatch({ + type: Action.UPDATE_TIME_ENTRIES, + timeEntries, }); -} +}; -export function searchOwnersCoverage(params) { - store.dispatch({ type: Action.OWNERS_COVERAGE_REQUEST }); - return new ApiRequest('/owners/wcbCglReport').get(params).then((response) => { - var ownersCoverage = normalize(response.data); +export const searchHiringReport = (params) => async (dispatch) => { + dispatch({ type: Action.HIRING_RESPONSES_REQUEST }); + const response = await dispatch(new ApiRequest('/rentalRequests/hireReport').get(params)); + let hiringResponses = normalize(response.data); - _.map(ownersCoverage, (entry) => { - entry.localAreaLabel = `${entry.serviceAreaId} - ${entry.localAreaName}`; - }); + _.map(hiringResponses, (entry) => { + entry.localAreaLabel = `${entry.serviceAreaId} - ${entry.localAreaName}`; + entry.equipmentDetails = [ + entry.equipmentMake || '-', + entry.equipmentModel || '-', + entry.equipmentSize || '-', + entry.equipmentYear || '-', + ].join('/'); + entry.sortableEquipmentCode = generateSortableEquipmentCode(entry); + }); - store.dispatch({ - type: Action.UPDATE_OWNERS_COVERAGE, - ownersCoverage: ownersCoverage, - }); + dispatch({ + type: Action.UPDATE_HIRING_RESPONSES, + hiringResponses, }); -} +}; -export function getProjects() { - const silent = store.getState().lookups.projects.loaded; - return new ApiRequest('/projects', { silent }).get({ currentFiscal: false }).then((response) => { - var projects = normalize(response.data); +export const searchOwnersCoverage = (params) => async (dispatch) => { + dispatch({ type: Action.OWNERS_COVERAGE_REQUEST }); + const response = await dispatch(new ApiRequest('/owners/wcbCglReport').get(params)); + let ownersCoverage = normalize(response.data); - // Add display fields - _.map(projects, (project) => { - parseProject(project); - }); + _.map(ownersCoverage, (entry) => { + entry.localAreaLabel = `${entry.serviceAreaId} - ${entry.localAreaName}`; + }); - store.dispatch({ - type: Action.UPDATE_PROJECTS_LOOKUP, - projects: projects, - }); + dispatch({ + type: Action.UPDATE_OWNERS_COVERAGE, + ownersCoverage, }); -} +}; -export function getProjectsAgreementSummary() { - const silent = store.getState().lookups.projectsAgreementSummary.loaded; - return new ApiRequest('/projects/agreementSummary', { silent }).get().then((response) => { - var projects = normalize(response.data); +export const getProjects = () => async (dispatch, getState) => { + const silent = getState().lookups.projects.loaded; + const response = await dispatch(new ApiRequest('/projects', { silent }).get({ currentFiscal: false })); + let projects = normalize(response.data); - store.dispatch({ - type: Action.UPDATE_PROJECTS_AGREEMENT_SUMMARY_LOOKUP, - projects: projects, - }); + // Add display fields + _.map(projects, (project) => { + dispatch(parseProject(project)); + }); + dispatch({ + type: Action.UPDATE_PROJECTS_LOOKUP, + projects, }); -} +}; +export const getProjectsAgreementSummary = () => async (dispatch, getState) => { + const silent = getState().lookups.projectsAgreementSummary.loaded; + const response = await dispatch(new ApiRequest('/projects/agreementSummary', { silent }).get()); + dispatch({ + type: Action.UPDATE_PROJECTS_AGREEMENT_SUMMARY_LOOKUP, + projects: response.data, + }); +}; -export function getProjectsCurrentFiscal() { - const silent = store.getState().lookups.projectsCurrentFiscal.loaded; - return new ApiRequest('/projects', { silent }).get({ currentFiscal: true }).then((response) => { - var projects = normalize(response.data); +export const getProjectsCurrentFiscal = () => async (dispatch, getState) => { + const silent = getState().lookups.projectsCurrentFiscal.loaded; + const response = await dispatch(new ApiRequest('/projects', { silent }).get({ currentFiscal: true })); + let projects = normalize(response.data); - // Add display fields - _.map(projects, (project) => { - parseProject(project); - }); + // Add display fields + _.map(projects, (project) => { + dispatch(parseProject(project)); + }); - store.dispatch({ - type: Action.UPDATE_PROJECTS_CURRENT_FISCAL_LOOKUP, - projects: projects, - }); + dispatch({ + type: Action.UPDATE_PROJECTS_CURRENT_FISCAL_LOOKUP, + projects, }); -} +}; -export function getProject(projectId) { - return new ApiRequest(`/projects/${projectId}`).get().then((response) => { - var project = response.data; +export const getProject = (projectId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/projects/${projectId}`).get()); + let project = response.data; - // Add display fields - parseProject(project); + // Add display fields + dispatch(parseProject(project)); - store.dispatch({ type: Action.UPDATE_PROJECT, project: project }); + dispatch({ type: Action.UPDATE_PROJECT, project }); - return project; - }); -} + return project; +}; -export function addProject(project) { - return new ApiRequest('/projects').post(project).then((response) => { - var project = response.data; +export const addProject = (project) => async (dispatch) => { + const response = await dispatch(new ApiRequest('/projects').post(project)); + let projectResponse = response.data; - // Add display fields - parseProject(project); + // Add display fields + dispatch(parseProject(projectResponse)); - store.dispatch({ type: Action.ADD_PROJECT, project: project }); + dispatch({ type: Action.ADD_PROJECT, project: projectResponse }); - return project; - }); -} + return projectResponse; +}; -export function updateProject(project) { +export const updateProject = (project) => async (dispatch) => { const projectData = _.omit( project, 'notes', @@ -1511,180 +1408,155 @@ export function updateProject(project) { ); projectData.projectId = project.id; - return new ApiRequest(`/projects/${project.id}`).put(projectData).then((response) => { - var project = response.data; + const response = await dispatch(new ApiRequest(`/projects/${project.id}`).put(projectData)); + let projectResponse = response.data; - // Add display fields - parseProject(project); + // Add display fields + dispatch(parseProject(projectResponse)); - store.dispatch({ type: Action.UPDATE_PROJECT, project: project }); - }); -} + dispatch({ type: Action.UPDATE_PROJECT, project: projectResponse }); +}; // XXX: Looks like this is unused -// export function getProjectEquipment(projectId) { -// return new ApiRequest(`/projects/${projectId}/equipment`).get().then(response => { -// var projectEquipment = normalize(response.data); - -// store.dispatch({ type: Action.UPDATE_PROJECT_EQUIPMENT, projectEquipment: projectEquipment }); -// }); -// } +// export const getProjectEquipment = (projectId) => async (dispatch) => { +// const response = await dispatch(new ApiRequest(`/projects/${projectId}/equipment`).get()); +// dispatch({ type: Action.UPDATE_PROJECT_EQUIPMENT, projectEquipment: normalize(response.data) }); +// }; // XXX: Looks like this is unused -// export function getProjectTimeRecords(projectId) { -// return new ApiRequest(`projects/${projectId}/timeRecords`).get().then(response => { -// var projectTimeRecords = normalize(response.data); - -// store.dispatch({ type: Action.UPDATE_PROJECT_TIME_RECORDS, projectTimeRecords: projectTimeRecords }); -// }); -// } +// export const getProjectTimeRecords = (projectId) => async (dispatch) => { +// const response = await dispatch(new ApiRequest(`projects/${projectId}/timeRecords`).get()); +// dispatch({ type: Action.UPDATE_PROJECT_TIME_RECORDS, projectTimeRecords: normalize(response.data) }); +// }; // XXX: Looks like this is unused -// export function addProjectTimeRecords(projectId, rentalRequestId, timeRecords) { -// let formattedTimeRecords = formatTimeRecords(timeRecords, rentalRequestId); -// return new ApiRequest(`projects/${projectId}/timeRecords`).post(formattedTimeRecords).then(response => { -// var projectTimeRecords = normalize(response.data); +// export const addProjectTimeRecords = (projectId, rentalRequestId, timeRecords) => async (dispatch) => { +// const formattedTimeRecords = formatTimeRecords(timeRecords, rentalRequestId); +// const response = await dispatch(new ApiRequest(`projects/${projectId}/timeRecords`).post(formattedTimeRecords)); +// const projectTimeRecords = normalize(response.data); -// store.dispatch({ type: Action.UPDATE_PROJECT_TIME_RECORDS, projectTimeRecords: projectTimeRecords }); -// return projectTimeRecords; -// }); -// } +// dispatch({ type: Action.UPDATE_PROJECT_TIME_RECORDS, projectTimeRecords }); +// return projectTimeRecords; +// }; -export function saveProjectContact(project, contact) { +export const saveProjectContact = (project, contact) => async (dispatch) => { const isNew = contact.id === 0; if (!isNew) { // don't update if this is a new contact - add after post() completes - store.dispatch({ + dispatch({ type: Action.UPDATE_PROJECT_CONTACT, projectId: project.id, contact, }); } - return new ApiRequest(`/projects/${project.id}/contacts/${contact.isPrimary}`).post(contact).then((response) => { - var updatedContact = response.data; - - // Add display fields - parseContact(updatedContact, project); // project's primary contact could be outdated - updatedContact.isPrimary = contact.isPrimary; - - if (isNew) { - // add newly created contact to Redux store's contacts - store.dispatch({ - type: Action.ADD_PROJECT_CONTACT, - projectId: project.id, - contact: updatedContact, - }); - } else { - // Update Redux store's data with the server's data - store.dispatch({ - type: Action.UPDATE_PROJECT_CONTACT, - projectId: project.id, - contact: updatedContact, - }); - } - - return updatedContact; - }); -} - -export function addProjectHistory(projectId, history) { - return new ApiRequest(`/projects/${projectId}/history`).post(history).then((response) => { - var history = normalize(response.data); - // Add display fields - _.map(history, (history) => { - parseHistory(history); - }); + const response = await dispatch(new ApiRequest(`/projects/${project.id}/contacts/${contact.isPrimary}`).post(contact)); + let updatedContact = response.data; - store.dispatch({ - type: Action.UPDATE_PROJECT_HISTORY, - history, - id: projectId, - }); + // Add display fields + parseContact(updatedContact, project); // project's primary contact could be outdated + updatedContact.isPrimary = contact.isPrimary; + + dispatch({ + type: isNew ? Action.ADD_PROJECT_CONTACT : Action.UPDATE_PROJECT_CONTACT, + projectId: project.id, + contact: updatedContact, }); -} -export function getProjectHistory(projectId, params) { - return new ApiRequest(`/projects/${projectId}/history`).get(params).then((response) => { - var history = normalize(response.data); + return updatedContact; +}; - // Add display fields - _.map(history, (history) => { - parseHistory(history); - }); +export const addProjectHistory = (projectId, history) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/projects/${projectId}/history`).post(history)); + let historyResponse = normalize(response.data); + // Add display fields + _.map(historyResponse, (h) => { + parseHistory(h); + }); - store.dispatch({ - type: Action.UPDATE_PROJECT_HISTORY, - history, - id: projectId, - }); + dispatch({ + type: Action.UPDATE_PROJECT_HISTORY, + history: historyResponse, + id: projectId, }); -} +}; -export function getProjectDocuments(projectId) { - return new ApiRequest(`/projects/${projectId}/attachments`).get().then((response) => { - var documents = normalize(response.data); +export const getProjectHistory = (projectId, params) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/projects/${projectId}/history`).get(params)); + let history = normalize(response.data); - // Add display fields - _.map(documents, (document) => { - parseDocument(document); - }); + // Add display fields + _.map(history, (h) => { + parseHistory(h); + }); - store.dispatch({ type: Action.UPDATE_DOCUMENTS, documents: documents }); + dispatch({ + type: Action.UPDATE_PROJECT_HISTORY, + history, + id: projectId, }); -} +}; -// XXX: Looks like this is unused -// export function addProjectDocument(projectId, files) { -// return new ApiRequest(`/projects/${ projectId }/attachments`).post(files); -// } - -export function getProjectNotes(projectId) { - return new ApiRequest(`/projects/${projectId}/notes`).get().then((response) => { - store.dispatch({ - type: Action.UPDATE_PROJECT_NOTES, - projectId, - notes: response.data, - }); - return response.data; +export const getProjectDocuments = (projectId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/projects/${projectId}/attachments`).get()); + let documents = normalize(response.data); + + // Add display fields + _.map(documents, (document) => { + parseDocument(document); }); -} -export function addProjectNote(projectId, note) { - store.dispatch({ type: Action.ADD_PROJECT_NOTE, projectId, note }); - return new ApiRequest(`/projects/${projectId}/note`).post(note); -} + dispatch({ type: Action.UPDATE_DOCUMENTS, documents }); +}; -export function getProjectRentalAgreements(projectId) { - return new ApiRequest(`/projects/${projectId}/rentalAgreements`).get().then((response) => { - var rentalAgreements = normalize(response.data); - store.dispatch({ - type: Action.UPDATE_PROJECT_RENTAL_AGREEMENTS, - rentalAgreements: rentalAgreements, - }); - return rentalAgreements; - }); -} - -export function cloneProjectRentalAgreement(data) { - return new ApiRequest(`/projects/${data.projectId}/rentalAgreementClone`).post(data).then((response) => { - var agreement = response.data; - // Add display fields - parseRentalAgreement(agreement); - store.dispatch({ - type: Action.UPDATE_RENTAL_AGREEMENT, - rentalAgreement: agreement, - }); - return response; +// XXX: Looks like this is unused +// export const addProjectDocument = (projectId, files) => async (dispatch) => { +// return await dispatch(new ApiRequest(`/projects/${ projectId }/attachments`).post(files)); +// }; + +export const getProjectNotes = (projectId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/projects/${projectId}/notes`).get()); + dispatch({ + type: Action.UPDATE_PROJECT_NOTES, + projectId, + notes: response.data, + }); + return response.data; +}; + +export const addProjectNote = (projectId, note) => async (dispatch) => { + dispatch({ type: Action.ADD_PROJECT_NOTE, projectId, note }); + return await dispatch(new ApiRequest(`/projects/${projectId}/note`).post(note)); +}; + +export const getProjectRentalAgreements = (projectId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/projects/${projectId}/rentalAgreements`).get()); + const rentalAgreements = normalize(response.data); + dispatch({ + type: Action.UPDATE_PROJECT_RENTAL_AGREEMENTS, + rentalAgreements, + }); + return rentalAgreements; +}; + +export const cloneProjectRentalAgreement = (data) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/projects/${data.projectId}/rentalAgreementClone`).post(data)); + let agreement = response.data; + // Add display fields + parseRentalAgreement(agreement); + dispatch({ + type: Action.UPDATE_RENTAL_AGREEMENT, + rentalAgreement: agreement, }); -} + return response; +}; //////////////////// // Rental Requests //////////////////// -function parseRentalRequest(rentalRequest) { +const parseRentalRequest = (rentalRequest) => (dispatch) => { if (!rentalRequest.localArea) { rentalRequest.localArea = { id: 0, name: '' }; } @@ -1771,203 +1643,194 @@ function parseRentalRequest(rentalRequest) { rentalRequest.url = `${rentalRequest.path}`; rentalRequest.name = 'TBD'; rentalRequest.historyEntity = History.makeHistoryEntity(Constant.HISTORY_REQUEST, rentalRequest); - rentalRequest.documentAdded = Log.rentalRequestDocumentAdded; - rentalRequest.documentsAdded = Log.rentalRequestDocumentsAdded; - rentalRequest.documentDeleted = Log.rentalRequestDocumentDeleted; + rentalRequest.documentAdded = (r, d) => dispatch(Log.rentalRequestDocumentAdded(r, d)); + rentalRequest.documentsAdded = (r) => dispatch(Log.rentalRequestDocumentsAdded(r)); + rentalRequest.documentDeleted = (r, d) => dispatch(Log.rentalRequestDocumentDeleted(r, d)); - rentalRequest.getDocumentsPromise = getRentalRequestDocuments; + rentalRequest.getDocumentsPromise = (requestRentalId) => dispatch(getRentalRequestDocuments(requestRentalId)); rentalRequest.uploadDocumentPath = `/rentalrequests/${rentalRequest.id}/attachments`; rentalRequest.canView = true; rentalRequest.canEdit = true; // HETS-894: view-only requests and requests that have yet to be acted on can be deleted rentalRequest.canDelete = rentalRequest.projectId === 0 || rentalRequest.yesCount === 0; -} +}; -export function searchRentalRequests(params) { - store.dispatch({ type: Action.RENTAL_REQUESTS_REQUEST }); - return new ApiRequest('/rentalrequests/search').get(params).then((response) => { - var rentalRequests = normalize(response.data); +export const searchRentalRequests = (params) => async (dispatch) => { + dispatch({ type: Action.RENTAL_REQUESTS_REQUEST }); + const response = await dispatch(new ApiRequest('/rentalrequests/search').get(params)); + let rentalRequests = normalize(response.data); - // Add display fields - _.map(rentalRequests, (req) => { - parseRentalRequest(req); - }); - - store.dispatch({ - type: Action.UPDATE_RENTAL_REQUESTS, - rentalRequests: rentalRequests, - }); + // Add display fields + _.map(rentalRequests, (req) => { + dispatch(parseRentalRequest(req)); }); -} -export function getRentalRequest(id) { - return new ApiRequest(`/rentalrequests/${id}`).get().then((response) => { - var rentalRequest = response.data; - // Add display fields - parseRentalRequest(rentalRequest); + dispatch({ + type: Action.UPDATE_RENTAL_REQUESTS, + rentalRequests, + }); +}; - store.dispatch({ - type: Action.UPDATE_RENTAL_REQUEST, - rentalRequest, - rentalRequestId: id, - }); +export const getRentalRequest = (id) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/rentalrequests/${id}`).get()); + let rentalRequest = response.data; + // Add display fields + dispatch(parseRentalRequest(rentalRequest)); - return rentalRequest; + dispatch({ + type: Action.UPDATE_RENTAL_REQUEST, + rentalRequest, + rentalRequestId: id, }); -} - -export function addRentalRequest(rentalRequest, viewOnly) { - var path = viewOnly ? '/rentalrequests/viewOnly' : '/rentalrequests'; - return new ApiRequest(path).post(rentalRequest).then((response) => { - var rentalRequest = response.data; - // Add display fields - parseRentalRequest(rentalRequest); - store.dispatch({ - type: Action.ADD_RENTAL_REQUEST, - rentalRequest, - rentalRequestId: rentalRequest.id, - }); + return rentalRequest; +}; - getEquipmentHires(); +export const addRentalRequest = (rentalRequest, viewOnly) => async (dispatch) => { + const path = viewOnly ? '/rentalrequests/viewOnly' : '/rentalrequests'; - return rentalRequest; + const response = await dispatch(new ApiRequest(path).post(rentalRequest)); + let rentalRequestResponse = response.data; + // Add display fields + dispatch(parseRentalRequest(rentalRequestResponse)); + dispatch({ + type: Action.ADD_RENTAL_REQUEST, + rentalRequest: rentalRequestResponse, + rentalRequestId: rentalRequestResponse.id, }); -} -export function updateRentalRequest(rentalRequest) { + dispatch(getEquipmentHires()); + rentalRequest.id = rentalRequestResponse.id; + return rentalRequest; +}; + +export const updateRentalRequest = (rentalRequest) => async (dispatch) => { // remove properties that interfere with deserialization const rentalRequestId = rentalRequest.id; - store.dispatch({ + dispatch({ type: Action.UPDATE_RENTAL_REQUEST, rentalRequest, rentalRequestId, }); - return new ApiRequest(`/rentalrequests/${rentalRequest.id}`) - .put(_.omit(rentalRequest, 'primaryContact')) - .then((response) => { - var rentalRequest = response.data; - // Add display fields - parseRentalRequest(rentalRequest); + const response = await dispatch( + new ApiRequest(`/rentalrequests/${rentalRequest.id}`) + .put(_.omit(rentalRequest, 'primaryContact'))); + + let rentalRequestResponse = response.data; + // Add display fields + dispatch(parseRentalRequest(rentalRequestResponse)); - store.dispatch({ - type: Action.UPDATE_RENTAL_REQUEST, - rentalRequest, - rentalRequestId, - }); - }); -} - -export function addRentalRequestHistory(requestId, history) { - return new ApiRequest(`/rentalrequests/${requestId}/history`).post(history).then((response) => { - var history = normalize(response.data); - // Add display fields - _.map(history, (history) => { - parseHistory(history); - }); + dispatch({ + type: Action.UPDATE_RENTAL_REQUEST, + rentalRequest: rentalRequestResponse, + rentalRequestId, + }); +}; - store.dispatch({ - type: Action.UPDATE_RENTAL_REQUEST_HISTORY, - history, - id: requestId, - }); +export const addRentalRequestHistory = (requestId, history) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/rentalrequests/${requestId}/history`).post(history)); + let historyResponse = normalize(response.data); + // Add display fields + _.map(historyResponse, (h) => { + parseHistory(h); }); -} -export function getRentalRequestHistory(requestId, params) { - return new ApiRequest(`/rentalrequests/${requestId}/history`).get(params).then((response) => { - var history = normalize(response.data); + dispatch({ + type: Action.UPDATE_RENTAL_REQUEST_HISTORY, + history: historyResponse, + id: requestId, + }); +}; - // Add display fields - _.map(history, (history) => { - parseHistory(history); - }); +export const getRentalRequestHistory = (requestId, params) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/rentalrequests/${requestId}/history`).get(params)); + let history = normalize(response.data); - store.dispatch({ - type: Action.UPDATE_RENTAL_REQUEST_HISTORY, - history, - id: requestId, - }); + // Add display fields + _.map(history, (h) => { + parseHistory(h); }); -} -export function getRentalRequestDocuments(rentalRequestId) { - return new ApiRequest(`/rentalrequests/${rentalRequestId}/attachments`).get().then((response) => { - var documents = normalize(response.data); + dispatch({ + type: Action.UPDATE_RENTAL_REQUEST_HISTORY, + history, + id: requestId, + }); +}; - // Add display fields - _.map(documents, (document) => { - parseDocument(document); - }); +export const getRentalRequestDocuments = (rentalRequestId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/rentalrequests/${rentalRequestId}/attachments`).get()); + let documents = normalize(response.data); - store.dispatch({ type: Action.UPDATE_DOCUMENTS, documents: documents }); + // Add display fields + _.map(documents, (document) => { + parseDocument(document); }); -} + + dispatch({ type: Action.UPDATE_DOCUMENTS, documents }); +}; // XXX: Looks like this is unused -// export function addRentalRequestDocument(rentalRequestId, files) { -// return new ApiRequest(`/rentalrequests/${ rentalRequestId }/attachments`).post(files); -// } - -export function getRentalRequestNotes(rentalRequestId) { - return new ApiRequest(`/rentalrequests/${rentalRequestId}/notes`).get().then((response) => { - store.dispatch({ - type: Action.UPDATE_RENTAL_REQUEST_NOTES, - notes: response.data, - rentalRequestId, - }); - return response.data; +// export const addRentalRequestDocument = (rentalRequestId, files) => async (dispatch) => { +// return await dispatch(new ApiRequest(`/rentalrequests/${ rentalRequestId }/attachments`).post(files)); +// }; + +export const getRentalRequestNotes = (rentalRequestId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/rentalrequests/${rentalRequestId}/notes`).get()); + dispatch({ + type: Action.UPDATE_RENTAL_REQUEST_NOTES, + notes: response.data, + rentalRequestId, }); -} + return response.data; +}; -export function addRentalRequestNote(rentalRequestId, note) { - return new ApiRequest(`/rentalRequests/${rentalRequestId}/note`).post(note).then((response) => { - store.dispatch({ - type: Action.UPDATE_RENTAL_REQUEST_NOTES, - notes: response.data, - rentalRequestId, - }); - return response.data; +export const addRentalRequestNote = (rentalRequestId, note) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/rentalRequests/${rentalRequestId}/note`).post(note)); + dispatch({ + type: Action.UPDATE_RENTAL_REQUEST_NOTES, + notes: response.data, + rentalRequestId, }); -} + return response.data; +}; -export function cancelRentalRequest(rentalRequestId) { - return new ApiRequest(`/rentalrequests/${rentalRequestId}/cancel`).get().then(() => { - getEquipmentHires(); - }); -} +export const cancelRentalRequest = (rentalRequestId) => async (dispatch) => { + await dispatch(new ApiRequest(`/rentalrequests/${rentalRequestId}/cancel`).get()); + dispatch(getEquipmentHires()); +}; -export function rentalRequestSeniorityList(rentalRequestId, counterCopy) { - var params = {}; +export const rentalRequestSeniorityList = (rentalRequestId, counterCopy) => async (dispatch) => { + const params = {}; if (counterCopy) { params.counterCopy = counterCopy; } - return new ApiRequest(`/rentalrequests/${rentalRequestId}/senioritylist`) - .get(params, { responseType: Constant.RESPONSE_TYPE_BLOB }) - .then((response) => { - return response; - }); -} + return await dispatch( + new ApiRequest(`/rentalrequests/${rentalRequestId}/senioritylist`) + .get(params, { responseType: Constant.RESPONSE_TYPE_BLOB })); +}; //////////////////// // Rental Request Rotation List //////////////////// -function getSeniorityDisplayName(blockNumber, numberOfBlocks, seniority, numberInBlock) { +const getSeniorityDisplayName = (blockNumber, numberOfBlocks, seniority, numberInBlock) => { if (blockNumber === numberOfBlocks) { return `Open-${seniority && seniority.toFixed(3)} (${numberInBlock})`; - } else if (blockNumber === 1) { + } + if (blockNumber === 1) { return `1-${seniority && seniority.toFixed(3)} (${numberInBlock})`; - } else if (blockNumber === 2) { + } + if (blockNumber === 2) { return `2-${seniority && seniority.toFixed(3)} (${numberInBlock})`; } return `Open-${seniority && seniority.toFixed(3)} (${numberInBlock})`; -} +}; -function parseRentalRequestRotationList(rotationListItem, rentalRequest = {}) { +const parseRentalRequestRotationList = (rotationListItem, rentalRequest = {}) => { if (!rotationListItem.rentalRequest) { rotationListItem.rentalRequest = _.extend({ id: 0 }, _.pick(rentalRequest, 'id')); } @@ -2033,9 +1896,9 @@ function parseRentalRequestRotationList(rotationListItem, rentalRequest = {}) { // TODO Status TBD rotationListItem.status = 'N/A'; -} +}; -function parseRotationListItem(item, numberOfBlocks, districtEquipmentType) { +const parseRotationListItem = (item, numberOfBlocks, districtEquipmentType) => { item.districtEquipmentType = districtEquipmentType; item.equipment = item.equipment || {}; item.equipment = { @@ -2065,56 +1928,55 @@ function parseRotationListItem(item, numberOfBlocks, districtEquipmentType) { item.equipment.numberInBlock ); - var primaryContact = item.equipment.owner && item.equipment.owner.primaryContact; + let primaryContact = item.equipment.owner && item.equipment.owner.primaryContact; item.displayFields.primaryContactName = primaryContact ? firstLastName(primaryContact.givenName, primaryContact.surname) : ''; -} +}; -export function getRentalRequestRotationList(id) { - return new ApiRequest(`/rentalrequests/${id}/rotationList`).get().then((response) => { - const rentalRequest = response.data; - const rotationList = rentalRequest.rentalRequestRotationList; +export const getRentalRequestRotationList = (id) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/rentalrequests/${id}/rotationList`).get()); + const rentalRequest = response.data; + let rotationList = rentalRequest.rentalRequestRotationList; - rotationList.map((item) => - parseRotationListItem(item, rentalRequest.numberOfBlocks, rentalRequest.districtEquipmentType) - ); + rotationList.map((item) => + parseRotationListItem(item, rentalRequest.numberOfBlocks, rentalRequest.districtEquipmentType) + ); - store.dispatch({ - type: Action.UPDATE_RENTAL_REQUEST_ROTATION_LIST, - rotationList, - rentalRequestId: id, - }); + dispatch({ + type: Action.UPDATE_RENTAL_REQUEST_ROTATION_LIST, + rotationList, + rentalRequestId: id, }); -} +}; -export function updateRentalRequestRotationList(rentalRequestRotationList, rentalRequest) { +export const updateRentalRequestRotationList = (rentalRequestRotationList, rentalRequest) => async (dispatch) => { const rentalRequestId = rentalRequest.id; - return new ApiRequest(`/rentalrequests/${rentalRequestId}/rentalRequestRotationList`) - .put(rentalRequestRotationList) - .then((response) => { - var rotationList = response.data.rentalRequestRotationList; - - rotationList.map((item) => - parseRotationListItem(item, rentalRequest.numberOfBlocks, rentalRequest.districtEquipmentType) - ); - - store.dispatch({ - type: Action.UPDATE_RENTAL_REQUEST_ROTATION_LIST, - rotationList, - rentalRequestId, - }); - - getEquipmentTs(); - getEquipmentHires(); - }); -} + const response = await dispatch( + new ApiRequest(`/rentalrequests/${rentalRequestId}/rentalRequestRotationList`) + .put(rentalRequestRotationList)); + + let rotationList = response.data.rentalRequestRotationList; + + rotationList.map((item) => + parseRotationListItem(item, rentalRequest.numberOfBlocks, rentalRequest.districtEquipmentType) + ); + + dispatch({ + type: Action.UPDATE_RENTAL_REQUEST_ROTATION_LIST, + rotationList, + rentalRequestId, + }); + + dispatch(getEquipmentTs()); + dispatch(getEquipmentHires()); +}; //////////////////// // Rental Agreements //////////////////// -function parseRentalAgreement(agreement) { +const parseRentalAgreement = (agreement) => { if (!agreement.district) { agreement.district = { id: 0, name: '' }; } @@ -2216,143 +2078,131 @@ function parseRentalAgreement(agreement) { // TODO HETS-115 Server needs to send this agreement.lastTimeRecord = agreement.lastTimeRecord || ''; -} +}; // reverse the transformations applied by the parse function -function convertRentalAgreement(agreement) { - return { - ...agreement, - rentalAgreementConditions: _.values(agreement.rentalAgreementConditions), - rentalAgreementRates: _.values(agreement.rentalAgreementRates), - overtimeRates: _.values(agreement.overtimeRates), - equipmentId: agreement.equipmentId || null, - projectId: agreement.projectId || null, - }; -} - -export function getRentalAgreementSummaryLite() { - return new ApiRequest('/rentalagreements/summaryLite').get().then((response) => { - var agreements = response.data; - - store.dispatch({ - type: Action.UPDATE_AGREEMENT_SUMMARY_LITE_LOOKUP, - agreements, - }); +const convertRentalAgreement = (agreement) => ({ + ...agreement, + rentalAgreementConditions: _.values(agreement.rentalAgreementConditions), + rentalAgreementRates: _.values(agreement.rentalAgreementRates), + overtimeRates: _.values(agreement.overtimeRates), + equipmentId: agreement.equipmentId || null, + projectId: agreement.projectId || null, +}); + +export const getRentalAgreementSummaryLite = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/rentalagreements/summaryLite').get()); + dispatch({ + type: Action.UPDATE_AGREEMENT_SUMMARY_LITE_LOOKUP, + agreements: response.data, + }); +}; + +export const getRentalAgreement = (id) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/rentalagreements/${id}`).get()); + let agreement = response.data; + + // Add display fields + parseRentalAgreement(agreement); + + dispatch({ + type: Action.UPDATE_RENTAL_AGREEMENT, + rentalAgreement: agreement, }); -} +}; -export function getRentalAgreement(id) { - return new ApiRequest(`/rentalagreements/${id}`).get().then((response) => { - var agreement = response.data; +export const getLatestRentalAgreement = (equipmentId, projectId) => async (dispatch) => { + const response = await dispatch( + new ApiRequest(`/rentalagreements/latest/${projectId}/${equipmentId}`).get()); - // Add display fields - parseRentalAgreement(agreement); + const agreement = response.data; - store.dispatch({ - type: Action.UPDATE_RENTAL_AGREEMENT, - rentalAgreement: agreement, - }); + dispatch({ + type: Action.UPDATE_RENTAL_AGREEMENT, + rentalAgreement: agreement, }); -} - -export function getLatestRentalAgreement(equipmentId, projectId) { - return new ApiRequest(`/rentalagreements/latest/${projectId}/${equipmentId}`).get().then((response) => { - var agreement = response.data; - store.dispatch({ - type: Action.UPDATE_RENTAL_AGREEMENT, - rentalAgreement: agreement, - }); - - return agreement; - }); -} + return agreement; +}; // XXX: Looks like this is unused -// export function addRentalAgreement(agreement) { -// return new ApiRequest('/rentalagreements').post(agreement).then(response => { -// var agreement = response.data; +// export const addRentalAgreement = (agreement) => async (dispatch) => { +// const response = await dispatch(new ApiRequest('/rentalagreements').post(agreement)); +// let agreement = response.data; -// // Add display fields -// parseRentalAgreement(agreement); +// // Add display fields +// parseRentalAgreement(agreement); -// store.dispatch({ type: Action.ADD_RENTAL_AGREEMENT, rentalAgreement: agreement }); -// }); -// } +// dispatch({ type: Action.ADD_RENTAL_AGREEMENT, rentalAgreement: agreement }); +// }; -export function updateRentalAgreement(agreement) { - var preparedAgreement = convertRentalAgreement(agreement); +export const updateRentalAgreement = (agreement) => async (dispatch) => { + const preparedAgreement = convertRentalAgreement(agreement); - store.dispatch({ + dispatch({ type: Action.UPDATE_RENTAL_AGREEMENT, rentalAgreement: preparedAgreement, }); - return new ApiRequest(`/rentalagreements/${agreement.id}`).put(preparedAgreement).then((response) => { - var agreement = response.data; + const response = await dispatch(new ApiRequest(`/rentalagreements/${agreement.id}`).put(preparedAgreement)); + let agreementResponse = response.data; - // Add display fields - parseRentalAgreement(agreement); + // Add display fields + parseRentalAgreement(agreementResponse); - store.dispatch({ - type: Action.UPDATE_RENTAL_AGREEMENT, - rentalAgreement: agreement, - }); + dispatch({ + type: Action.UPDATE_RENTAL_AGREEMENT, + rentalAgreement: agreementResponse, }); -} +}; -export function getRentalAgreementTimeRecords(rentalAgreementId) { - return new ApiRequest(`/rentalagreements/${rentalAgreementId}/timeRecords`).get().then((response) => { - var rentalAgreementTimeRecords = response.data; - - store.dispatch({ - type: Action.RENTAL_AGREEMENT_TIME_RECORDS, - rentalAgreementTimeRecords: rentalAgreementTimeRecords, - }); +export const getRentalAgreementTimeRecords = (rentalAgreementId) => async (dispatch) => { + const response = await dispatch( + new ApiRequest(`/rentalagreements/${rentalAgreementId}/timeRecords`).get()); + + dispatch({ + type: Action.RENTAL_AGREEMENT_TIME_RECORDS, + rentalAgreementTimeRecords: response.data, }); -} - -export function addRentalAgreementTimeRecords(rentalRequestId, timeRecords) { - let formattedTimeRecords = formatTimeRecords(timeRecords, rentalRequestId); - return new ApiRequest(`/rentalagreements/${rentalRequestId}/timeRecords`) - .post(formattedTimeRecords) - .then((response) => { - var rentalAgreementTimeRecords = normalize(response.data.timeRecords); +}; - store.dispatch({ - type: Action.RENTAL_AGREEMENT_TIME_RECORDS, - rentalAgreementTimeRecords: rentalAgreementTimeRecords, - }); - return rentalAgreementTimeRecords; - }); -} +export const addRentalAgreementTimeRecords = (rentalRequestId, timeRecords) => async (dispatch) => { + const formattedTimeRecords = formatTimeRecords(timeRecords, rentalRequestId); + const response = await dispatch( + new ApiRequest(`/rentalagreements/${rentalRequestId}/timeRecords`) + .post(formattedTimeRecords)); + + const rentalAgreementTimeRecords = normalize(response.data.timeRecords); -export function releaseRentalAgreement(rentalAgreementId) { - return new ApiRequest(`/rentalagreements/${rentalAgreementId}/release`).post().then((response) => { - return response; + dispatch({ + type: Action.RENTAL_AGREEMENT_TIME_RECORDS, + rentalAgreementTimeRecords, }); -} + return rentalAgreementTimeRecords; +}; -export function generateRentalAgreementDocument(rentalAgreementId) { - return new ApiRequest(`/rentalagreements/${rentalAgreementId}/doc`); -} +export const releaseRentalAgreement = (rentalAgreementId) => async (dispatch) => { + return await dispatch(new ApiRequest(`/rentalagreements/${rentalAgreementId}/release`).post()); +}; -export function searchAitReport(params) { - store.dispatch({ type: Action.AIT_REPORT_REQUEST }); - return new ApiRequest('/rentalAgreements/aitReport').get(params).then((response) => { - var aitResponses = normalize(response.data); - store.dispatch({ - type: Action.UPDATE_AIT_REPORT, - aitResponses: aitResponses, - }); +export const generateRentalAgreementDocument = (rentalAgreementId) => async (dispatch) => { + return await dispatch(new ApiRequest(`/rentalagreements/${rentalAgreementId}/doc`).getBlob()); +}; + +export const searchAitReport = (params) => async (dispatch) => { + dispatch({ type: Action.AIT_REPORT_REQUEST }); + const response = await dispatch(new ApiRequest('/rentalAgreements/aitReport').get(params)); + dispatch({ + type: Action.UPDATE_AIT_REPORT, + aitResponses: normalize(response.data), }); -} +}; //////////////////// // Rental Rates //////////////////// -function parseRentalRate(rentalRate, parent = {}) { +const parseRentalRate = (rentalRate, parent = {}) => { // Pick only the properties that we need if (!rentalRate.rentalAgreement) { rentalRate.rentalAgreement = _.extend( @@ -2380,108 +2230,108 @@ function parseRentalRate(rentalRate, parent = {}) { rentalRate.canEdit = true; rentalRate.canDelete = true; -} +}; // XXX: Looks like this is unused -// export function getRentalRate(id) { -// return new ApiRequest(`/rentalagreementrates/${ id }`).get().then(response => { -// var rentalRate = response.data; +// export const getRentalRate = (id) => async (dispatch) => { +// const response = await dispatch(new ApiRequest(`/rentalagreementrates/${ id }`).get()); +// let rentalRate = response.data; -// // Add display fields -// parseRentalRate(rentalRate); +// // Add display fields +// parseRentalRate(rentalRate); -// store.dispatch({ type: Action.UPDATE_RENTAL_RATE, rentalRate: rentalRate }); -// }); -// } +// dispatch({ type: Action.UPDATE_RENTAL_RATE, rentalRate }); +// }; -// export function addRentalRate(rentalRate) { -// return new ApiRequest('/rentalagreementrates').post({ ...rentalRate, rentalAgreement: { id: rentalRate.rentalAgreement.id } }).then(response => { -// var rentalRate = response.data; +// export const addRentalRate = (rentalRate) => async (dispatch) => { +// const response = await dispatch( +// new ApiRequest('/rentalagreementrates') +// .post({ ...rentalRate, rentalAgreement: { id: rentalRate.rentalAgreement.id } })); -// // Add display fields -// parseRentalRate(rentalRate); +// let rentalRate = response.data; -// store.dispatch({ type: Action.ADD_RENTAL_RATE, rentalRate }); -// }); -// } +// // Add display fields +// parseRentalRate(rentalRate); -export function addRentalRates(rentalAgreementId, rentalRates) { - store.dispatch({ +// dispatch({ type: Action.ADD_RENTAL_RATE, rentalRate }); +// }; + +export const addRentalRates = (rentalAgreementId, rentalRates) => async (dispatch) => { + dispatch({ type: Action.ADD_RENTAL_RATES, rentalRates, rentalAgreementId, }); - return new ApiRequest(`/rentalagreements/${rentalAgreementId}/rateRecords`).post(rentalRates).then((response) => { - const data = _.find(response.data, { rentalAgreementId }); - var rentalRates = data.rentalAgreement.rentalAgreementRates; - - // Add display fields - rentalRates.forEach((rentalRate) => parseRentalRate(rentalRate, data.rentalAgreement)); + const response = await dispatch( + new ApiRequest(`/rentalagreements/${rentalAgreementId}/rateRecords`).post(rentalRates)); + + const data = _.find(response.data, { rentalAgreementId }); + let rates = data.rentalAgreement.rentalAgreementRates; - store.dispatch({ - type: Action.UPDATE_RENTAL_RATES, - rentalRates, - rentalAgreementId, - }); + // Add display fields + rates.forEach((rentalRate) => parseRentalRate(rentalRate, data.rentalAgreement)); - return rentalRates; + dispatch({ + type: Action.UPDATE_RENTAL_RATES, + rentalRates: rates, + rentalAgreementId, }); -} -export function updateRentalRate(rentalRate) { + return rates; +}; + +export const updateRentalRate = (rentalRate) => async (dispatch) => { const rentalAgreementId = rentalRate.rentalAgreement.id; - store.dispatch({ + dispatch({ type: Action.UPDATE_RENTAL_RATES, rentalRates: [rentalRate], rentalAgreementId, }); - return new ApiRequest(`/rentalagreementrates/${rentalRate.id}`).put(rentalRate).then((response) => { - var rentalRate = response.data; - - // Add display fields - parseRentalRate(rentalRate); + const response = await dispatch(new ApiRequest(`/rentalagreementrates/${rentalRate.id}`).put(rentalRate)); + let rate = response.data; - store.dispatch({ - type: Action.UPDATE_RENTAL_RATES, - rentalRates: [rentalRate], - rentalAgreementId, - }); + // Add display fields + parseRentalRate(rate); - return rentalRate; + dispatch({ + type: Action.UPDATE_RENTAL_RATES, + rentalRates: [rate], + rentalAgreementId, }); -} -export function deleteRentalRate(rentalRate) { + return rentalRate; +}; + +export const deleteRentalRate = (rentalRate) => async (dispatch) => { const rentalAgreementId = rentalRate.rentalAgreement.id; - store.dispatch({ + dispatch({ type: Action.DELETE_RENTAL_RATE, rentalRate, rentalAgreementId, }); - return new ApiRequest(`/rentalagreementrates/${rentalRate.id}/delete`).post().then((response) => { - const rentalRate = response.data; - - // Add display fields - parseRentalRate(rentalRate); + const response = await dispatch(new ApiRequest(`/rentalagreementrates/${rentalRate.id}/delete`).post()); + let rate = response.data; - store.dispatch({ - type: Action.DELETE_RENTAL_RATE, - rentalRate, - rentalAgreementId, - }); + // Add display fields + parseRentalRate(rate); - return rentalRate; + dispatch({ + type: Action.DELETE_RENTAL_RATE, + rentalRate: rate, + rentalAgreementId, }); -} + + return rate; +}; //////////////////// // Rental Conditions //////////////////// -function parseRentalCondition(rentalCondition, parent = {}) { +const parseRentalCondition = (rentalCondition, parent = {}) => { // Pick only the properties that we need if (!rentalCondition.rentalAgreement) { rentalCondition.rentalAgreement = _.extend({ id: 0 }, _.pick(parent, 'id', 'number', 'path')); @@ -2500,473 +2350,417 @@ function parseRentalCondition(rentalCondition, parent = {}) { rentalCondition.canEdit = true; rentalCondition.canDelete = true; -} +}; // XXX: Looks like this is unused -// export function getRentalCondition(id) { -// return new ApiRequest(`/rentalagreementconditions/${ id }`).get().then(response => { -// var rentalCondition = response.data; +// export const getRentalCondition = (id) => async (dispatch) => { +// const response = await dispatch(new ApiRequest(`/rentalagreementconditions/${ id }`).get()); +// let rentalCondition = response.data; -// // Add display fields -// parseRentalCondition(rentalCondition); +// // Add display fields +// parseRentalCondition(rentalCondition); -// store.dispatch({ type: Action.UPDATE_RENTAL_CONDITION, rentalCondition: rentalCondition }); -// }); -// } +// dispatch({ type: Action.UPDATE_RENTAL_CONDITION, rentalCondition }); +// }; // XXX: Looks like this is unused -// export function addRentalCondition(rentalCondition) { -// return new ApiRequest('/rentalagreementconditions').post({ ...rentalCondition, rentalAgreement: { id: rentalCondition.rentalAgreement.id } }).then(response => { -// var rentalCondition = response.data; +// export const addRentalCondition = (rentalCondition) => async (dispatch) => { +// const response = await dispatch( +// new ApiRequest('/rentalagreementconditions') +// .post({ ...rentalCondition, rentalAgreement: { id: rentalCondition.rentalAgreement.id } })); + +// let rentalCondition = response.data; -// // Add display fields -// parseRentalCondition(rentalCondition); +// // Add display fields +// parseRentalCondition(rentalCondition); -// store.dispatch({ type: Action.ADD_RENTAL_CONDITION, rentalCondition: rentalCondition }); -// }); -// } +// dispatch({ type: Action.ADD_RENTAL_CONDITION, rentalCondition }); +// }; -export function addRentalConditions(rentalAgreementId, rentalConditions) { - store.dispatch({ +export const addRentalConditions = (rentalAgreementId, rentalConditions) => async (dispatch) => { + dispatch({ type: Action.ADD_RENTAL_CONDITIONS, rentalConditions, rentalAgreementId, }); - return new ApiRequest(`/rentalagreements/${rentalAgreementId}/conditionRecords`) - .post(rentalConditions) - .then((response) => { - const data = _.find(response.data, { rentalAgreementId }); - var rentalConditions = data.rentalAgreement.rentalAgreementConditions; + const response = await dispatch( + new ApiRequest(`/rentalagreements/${rentalAgreementId}/conditionRecords`) + .post(rentalConditions)); - // Add display fields - rentalConditions.forEach((rentalCondition) => parseRentalCondition(rentalCondition, data.rentalAgreement)); + const data = _.find(response.data, { rentalAgreementId }); + let conditions = data.rentalAgreement.rentalAgreementConditions; - store.dispatch({ - type: Action.UPDATE_RENTAL_CONDITIONS, - rentalConditions, - rentalAgreementId, - }); + // Add display fields + conditions.forEach((rentalCondition) => parseRentalCondition(rentalCondition, data.rentalAgreement)); - return rentalConditions; - }); -} + dispatch({ + type: Action.UPDATE_RENTAL_CONDITIONS, + rentalConditions: conditions, + rentalAgreementId, + }); -export function updateRentalCondition(rentalCondition) { + return conditions; +}; + +export const updateRentalCondition = (rentalCondition) => async (dispatch) => { const rentalAgreementId = rentalCondition.rentalAgreement.id; - store.dispatch({ + dispatch({ type: Action.UPDATE_RENTAL_CONDITIONS, rentalConditions: [rentalCondition], rentalAgreementId, }); - return new ApiRequest(`/rentalagreementconditions/${rentalCondition.id}`).put(rentalCondition).then((response) => { - var rentalCondition = response.data; - - // Add display fields - parseRentalCondition(rentalCondition); + const response = await dispatch( + new ApiRequest(`/rentalagreementconditions/${rentalCondition.id}`).put(rentalCondition)); + + let condition = response.data; - store.dispatch({ - type: Action.UPDATE_RENTAL_CONDITIONS, - rentalConditions: [rentalCondition], - rentalAgreementId, - }); + // Add display fields + parseRentalCondition(condition); - return rentalCondition; + dispatch({ + type: Action.UPDATE_RENTAL_CONDITIONS, + rentalConditions: [condition], + rentalAgreementId, }); -} -export function deleteRentalCondition(rentalCondition) { + return condition; +}; + +export const deleteRentalCondition = (rentalCondition) => async (dispatch) => { const rentalAgreementId = rentalCondition.rentalAgreement.id; - store.dispatch({ + dispatch({ type: Action.DELETE_RENTAL_CONDITION, rentalCondition, rentalAgreementId, }); - return new ApiRequest(`/rentalagreementconditions/${rentalCondition.id}/delete`).post().then((response) => { - var rentalCondition = response.data; - - // Add display fields - parseRentalCondition(rentalCondition); + const response = await dispatch( + new ApiRequest(`/rentalagreementconditions/${rentalCondition.id}/delete`).post()); + + let condition = response.data; - store.dispatch({ - type: Action.DELETE_RENTAL_CONDITION, - rentalCondition, - rentalAgreementId, - }); + // Add display fields + parseRentalCondition(condition); - return rentalCondition; + dispatch({ + type: Action.DELETE_RENTAL_CONDITION, + rentalCondition: condition, + rentalAgreementId, }); -} -export function deleteCondition(id) { - return new ApiRequest(`/conditiontypes/${id}/delete`).post().then((response) => { - return response; - }); -} + return condition; +}; -export function addCondition(condition) { - return new ApiRequest('/conditiontypes/0').post(condition).then((response) => { - return response; - }); -} +export const deleteCondition = (id) => async (dispatch) => { + return await dispatch(new ApiRequest(`/conditiontypes/${id}/delete`).post()); +}; -export function updateCondition(condition) { - return new ApiRequest(`/conditiontypes/${condition.id}`).post(condition).then((response) => { - return response; - }); -} +export const addCondition = (condition) => async (dispatch) => { + return await dispatch(new ApiRequest('/conditiontypes/0').post(condition)); +}; + +export const updateCondition = (condition) => async (dispatch) => { + return await dispatch(new ApiRequest(`/conditiontypes/${condition.id}`).post(condition)); +}; //////////////////// // Business //////////////////// -export function getBusiness() { - return new ApiRequest('/business').get().then((response) => { - var business = response.data; +export const getBusiness = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/business').get()); + let business = response.data; - if (!_.isObject(business)) { - business = {}; - } + if (!_.isObject(business)) { + business = {}; + } - _.map(business.owners, (owner) => { - parseOwner(owner); - }); - store.dispatch({ type: Action.UPDATE_BUSINESS, business: business }); + _.map(business.owners, (owner) => { + dispatch(parseOwner(owner)); }); -} -export function getOwnerForBusiness(ownerId) { - return new ApiRequest(`/business/owner/${ownerId}`).get().then((response) => { - var owner = response.data; + dispatch({ type: Action.UPDATE_BUSINESS, business }); +}; - parseOwner(owner); - store.dispatch({ type: Action.UPDATE_OWNER, owner: owner }); - }); -} +export const getOwnerForBusiness = (ownerId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/business/owner/${ownerId}`).get()); + let owner = response.data; -export function validateOwner(secretKey, postalCode) { - return new ApiRequest('/business/validateOwner') - .get({ sharedKey: secretKey, postalCode: postalCode }) - .then((response) => { - var business = response.data; - parseOwner(business.linkedOwner); - store.dispatch({ type: Action.UPDATE_BUSINESS, business: business }); - }); -} + dispatch(parseOwner(owner)); + dispatch({ type: Action.UPDATE_OWNER, owner }); +}; + +export const validateOwner = (secretKey, postalCode) => async (dispatch) => { + const response = await dispatch( + new ApiRequest('/business/validateOwner') + .get({ sharedKey: secretKey, postalCode })); + + let business = response.data; + dispatch(parseOwner(business.linkedOwner)); + dispatch({ type: Action.UPDATE_BUSINESS, business }); +}; //////////////////// // Rollovers //////////////////// -function parseRolloverStatus(status) { +const parseRolloverStatus = (status) => { status.rolloverActive = status.progressPercentage != null && status.progressPercentage >= 0 && status.progressPercentage < 100; status.rolloverComplete = status.progressPercentage === 100; -} - -export function getRolloverStatus(districtId) { - return new ApiRequest(`/districts/${districtId}/rolloverStatus`).get(null, { silent: true }).then((response) => { - var status = response.data; - parseRolloverStatus(status); - store.dispatch({ - type: Action.UPDATE_ROLLOVER_STATUS_LOOKUP, - status: status, - }); - }); -} - -export function initiateRollover(districtId) { - return new ApiRequest(`/districts/${districtId}/annualRollover`).get().then((response) => { - var status = response; - parseRolloverStatus(status); - store.dispatch({ - type: Action.UPDATE_ROLLOVER_STATUS_LOOKUP, - status: status, - }); - }); -} - -export function dismissRolloverMessage(districtId) { - return new ApiRequest(`/districts/${districtId}/dismissRolloverMessage`).post().then((response) => { - var status = response.data; - parseRolloverStatus(status); - store.dispatch({ - type: Action.UPDATE_ROLLOVER_STATUS_LOOKUP, - status: status, - }); - }); -} +}; + +export const getRolloverStatus = (districtId) => async (dispatch) => { + const response = await dispatch( + new ApiRequest(`/districts/${districtId}/rolloverStatus`) + .get(null, { silent: true })); + + let status = response.data; + parseRolloverStatus(status); + dispatch({ + type: Action.UPDATE_ROLLOVER_STATUS_LOOKUP, + status, + }); +}; + +export const initiateRollover = (districtId) => async (dispatch) => { + const response = await dispatch( + new ApiRequest(`/districts/${districtId}/annualRollover`).get()); + + let status = response; + parseRolloverStatus(status); + dispatch({ + type: Action.UPDATE_ROLLOVER_STATUS_LOOKUP, + status, + }); +}; + +export const dismissRolloverMessage = (districtId) => async (dispatch) => { + const response = await dispatch( + new ApiRequest(`/districts/${districtId}/dismissRolloverMessage`).post()); + + let status = response.data; + parseRolloverStatus(status); + dispatch({ + type: Action.UPDATE_ROLLOVER_STATUS_LOOKUP, + status, + }); +}; //////////////////// // Look-ups //////////////////// // XXX: Looks like this is unused -// export function getCities() { -// return new ApiRequest('/cities').get().then(response => { -// var cities = normalize(response.data); - -// store.dispatch({ type: Action.UPDATE_CITIES_LOOKUP, cities: cities }); -// }); -// } - -export function getDistricts() { - return new ApiRequest('/districts').get().then((response) => { - var districts = normalize(response.data); - - store.dispatch({ - type: Action.UPDATE_DISTRICTS_LOOKUP, - districts: districts, - }); - }); -} - -export function getRegions() { - return new ApiRequest('/regions').get().then((response) => { - var regions = normalize(response.data); - - store.dispatch({ type: Action.UPDATE_REGIONS_LOOKUP, regions: regions }); - }); -} +// export const getCities = () => async (dispatch) => { +// const response = await dispatch(new ApiRequest('/cities').get()); +// dispatch({ type: Action.UPDATE_CITIES_LOOKUP, cities: normalize(response.data) }); +// }; + +export const getDistricts = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/districts').get()); + dispatch({ + type: Action.UPDATE_DISTRICTS_LOOKUP, + districts: normalize(response.data), + }); +}; + +export const getRegions = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/regions').get()); + dispatch({ type: Action.UPDATE_REGIONS_LOOKUP, regions: normalize(response.data) }); +}; + +export const getLocalAreas = (id) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/districts/${id}/localAreas`).get()); + let localAreas = normalize(response.data); + _.map(localAreas, (area) => (area.name = `${area.serviceAreaId} - ${area.name}`)); + + dispatch({ + type: Action.UPDATE_LOCAL_AREAS_LOOKUP, + localAreas, + }); +}; + +export const getServiceAreas = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/serviceareas').get()); + dispatch({ + type: Action.UPDATE_SERVICE_AREAS_LOOKUP, + serviceAreas: normalize(response.data), + }); +}; + +export const getEquipmentTypes = () => async (dispatch, getState) => { + const silent = getState().lookups.equipmentTypes.loaded; + const response = await dispatch(new ApiRequest('/equipmenttypes', { silent }).get()); + let equipmentTypes = _.mapValues(normalize(response.data), (x) => { + x.blueBookSectionAndName = `${x.blueBookSection} - ${x.name}`; + return x; + }); + + dispatch({ + type: Action.UPDATE_EQUIPMENT_TYPES_LOOKUP, + equipmentTypes, + }); +}; + +export const getDistrictEquipmentTypes = () => async (dispatch, getState) => { + const silent = getState().lookups.districtEquipmentTypes.loaded; + const response = await dispatch(new ApiRequest('/districtequipmenttypes', { silent }).get()); + dispatch({ + type: Action.UPDATE_DISTRICT_EQUIPMENT_TYPES_LOOKUP, + districtEquipmentTypes: normalize(response.data), + }); +}; + +export const getDistrictEquipmentTypesAgreementSummary = () => async (dispatch, getState) => { + const silent = getState().lookups.districtEquipmentTypesAgreementSummary.loaded; + const response = await dispatch( + new ApiRequest('/districtequipmenttypes/agreementSummary', { silent }).get()); + + dispatch({ + type: Action.UPDATE_DISTRICT_EQUIPMENT_TYPES_AGREEMENT_SUMMARY_LOOKUP, + districtEquipmentTypes: response.data, + }); +}; + +export const getFiscalYears = (districtId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/districts/${districtId}/fiscalYears`).get()); + dispatch({ + type: Action.UPDATE_FISCAL_YEARS_LOOKUP, + fiscalYears: response.data, + }); +}; + +export const getOwnersLite = () => async (dispatch, getState) => { + const silent = getState().lookups.owners.lite.loaded; + const response = await dispatch(new ApiRequest('/owners/lite', { silent }).get()); + dispatch({ type: Action.UPDATE_OWNERS_LITE_LOOKUP, owners: normalize(response.data) }); +}; + +export const getOwnersLiteHires = () => async (dispatch, getState) => { + const silent = getState().lookups.owners.hires.loaded; + const response = await dispatch(new ApiRequest('/owners/liteHires', { silent }).get()); + dispatch({ + type: Action.UPDATE_OWNERS_LITE_HIRES_LOOKUP, + owners: normalize(response.data), + }); +}; + +export const getOwnersLiteTs = () => async (dispatch, getState) => { + const silent = getState().lookups.owners.ts.loaded; + const response = await dispatch(new ApiRequest('/owners/liteTs', { silent }).get()); + dispatch({ + type: Action.UPDATE_OWNERS_LITE_TS_LOOKUP, + owners: normalize(response.data), + }); +}; + +export const addDistrictEquipmentType = (equipment) => async (dispatch) => { + return await dispatch(new ApiRequest(`/districtequipmenttypes/${equipment.id}`).post(equipment)); +}; + +export const updateDistrictEquipmentType = (equipment) => async (dispatch) => { + return await dispatch(new ApiRequest(`/districtequipmenttypes/${equipment.id}`).post(equipment)); +}; -export function getLocalAreas(id) { - return new ApiRequest(`/districts/${id}/localAreas`).get().then((response) => { - var localAreas = normalize(response.data); - _.map(localAreas, (area) => (area.name = `${area.serviceAreaId} - ${area.name}`)); - - store.dispatch({ - type: Action.UPDATE_LOCAL_AREAS_LOOKUP, - localAreas: localAreas, - }); - }); -} - -export function getServiceAreas() { - return new ApiRequest('/serviceareas').get().then((response) => { - var serviceAreas = normalize(response.data); - - store.dispatch({ - type: Action.UPDATE_SERVICE_AREAS_LOOKUP, - serviceAreas: serviceAreas, - }); - }); -} - -export function getEquipmentTypes() { - const silent = store.getState().lookups.equipmentTypes.loaded; - return new ApiRequest('/equipmenttypes', { silent }).get().then((response) => { - var equipmentTypes = _.mapValues(normalize(response.data), (x) => { - x.blueBookSectionAndName = `${x.blueBookSection} - ${x.name}`; - return x; - }); - - store.dispatch({ - type: Action.UPDATE_EQUIPMENT_TYPES_LOOKUP, - equipmentTypes, - }); +export const deleteDistrictEquipmentType = (equipment) => async (dispatch) => { + return await dispatch(new ApiRequest(`/districtequipmenttypes/${equipment.id}/delete`).post()); +}; + +export const getRoles = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/roles').get()); + dispatch({ type: Action.UPDATE_ROLES_LOOKUP, roles: normalize(response.data) }); +}; + +export const getPermissions = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/permissions').get()); + dispatch({ + type: Action.UPDATE_PERMISSIONS_LOOKUP, + permissions: normalize(response.data), }); -} - -export function getDistrictEquipmentTypes() { - const silent = store.getState().lookups.districtEquipmentTypes.loaded; - return new ApiRequest('/districtequipmenttypes', { silent }).get().then((response) => { - var districtEquipmentTypes = normalize(response.data); - - store.dispatch({ - type: Action.UPDATE_DISTRICT_EQUIPMENT_TYPES_LOOKUP, - districtEquipmentTypes: districtEquipmentTypes, - }); - }); -} - -export function getDistrictEquipmentTypesAgreementSummary() { - const silent = store.getState().lookups.districtEquipmentTypesAgreementSummary.loaded; - - - return new ApiRequest('/districtequipmenttypes/agreementSummary', { silent }).get().then((response) => { - var districtEquipmentTypes = normalize(response.data); - - store.dispatch({ - type: Action.UPDATE_DISTRICT_EQUIPMENT_TYPES_AGREEMENT_SUMMARY_LOOKUP, - districtEquipmentTypes, - }); - - - - }); -} - -export function getFiscalYears(districtId) { - return new ApiRequest(`/districts/${districtId}/fiscalYears`).get().then((response) => { - store.dispatch({ - type: Action.UPDATE_FISCAL_YEARS_LOOKUP, - fiscalYears: response.data, - }); - }); -} - -export function getOwnersLite() { - const silent = store.getState().lookups.owners.lite.loaded; - return new ApiRequest('/owners/lite', { silent }).get().then((response) => { - var owners = normalize(response.data); - store.dispatch({ type: Action.UPDATE_OWNERS_LITE_LOOKUP, owners: owners }); - }); -} - -export function getOwnersLiteHires() { - const silent = store.getState().lookups.owners.hires.loaded; - return new ApiRequest('/owners/liteHires', { silent }).get().then((response) => { - var owners = normalize(response.data); - store.dispatch({ - type: Action.UPDATE_OWNERS_LITE_HIRES_LOOKUP, - owners: owners, - }); - }); -} - -export function getOwnersLiteTs() { - const silent = store.getState().lookups.owners.ts.loaded; - return new ApiRequest('/owners/liteTs', { silent }).get().then((response) => { - var owners = normalize(response.data); - - store.dispatch({ - type: Action.UPDATE_OWNERS_LITE_TS_LOOKUP, - owners: owners, - }); - }); -} - -export function addDistrictEquipmentType(equipment) { - return new ApiRequest(`/districtequipmenttypes/${equipment.id}`).post(equipment).then((response) => { - return response; - }); -} - -export function updateDistrictEquipmentType(equipment) { - return new ApiRequest(`/districtequipmenttypes/${equipment.id}`).post(equipment).then((response) => { - return response; - }); -} - -export function deleteDistrictEquipmentType(equipment) { - return new ApiRequest(`/districtequipmenttypes/${equipment.id}/delete`).post().then((response) => { - return response; - }); -} - -export function getRoles() { - return new ApiRequest('/roles').get().then((response) => { - var roles = normalize(response.data); - - store.dispatch({ type: Action.UPDATE_ROLES_LOOKUP, roles: roles }); - }); -} - -export function getPermissions() { - return new ApiRequest('/permissions').get().then((response) => { - var permissions = normalize(response.data); - - store.dispatch({ - type: Action.UPDATE_PERMISSIONS_LOOKUP, - permissions: permissions, - }); - }); -} +}; // XXX: Looks like this is unused -// export function getProvincialRateTypes() { -// return new ApiRequest('/provincialratetypes').get().then(response => { -// var rateTypeOther = { -// id: 10000, -// rateType: 'OTHER', -// description: Constant.NON_STANDARD_CONDITION, -// rate: null, -// isPercentRate: false, -// isRateEditable: true, -// isIncludedInTotal: false, -// isInTotalEditable: true, -// }; -// var provincialRateTypes = [ ...response.data, rateTypeOther ]; - -// store.dispatch({ type: Action.UPDATE_PROVINCIAL_RATE_TYPES_LOOKUP, provincialRateTypes: provincialRateTypes }); -// }); -// } - -export function getOvertimeRateTypes() { - return new ApiRequest('/provincialratetypes/overtime').get().then((response) => { - store.dispatch({ - type: Action.UPDATE_OVERTIME_RATE_TYPES_LOOKUP, - overtimeRateTypes: response.data, - }); - }); -} - -export function updateOvertimeRateType(rate) { - return new ApiRequest(`/provincialratetypes/${rate.id}`).put(rate).then((response) => { - return response; - }); -} - -export function getRentalConditions() { - store.dispatch({ type: Action.RENTAL_CONDITIONS_LOOKUP_REQUEST }); - return new ApiRequest('/conditiontypes').get().then((response) => { - var rentalConditions = response.data; - - store.dispatch({ - type: Action.UPDATE_RENTAL_CONDITIONS_LOOKUP, - rentalConditions: rentalConditions, - }); - }); -} +// export const getProvincialRateTypes = () => async (dispatch) => { +// const response = await dispatch(new ApiRequest('/provincialratetypes').get()); +// const rateTypeOther = { +// id: 10000, +// rateType: 'OTHER', +// description: Constant.NON_STANDARD_CONDITION, +// rate: null, +// isPercentRate: false, +// isRateEditable: true, +// isIncludedInTotal: false, +// isInTotalEditable: true, +// }; +// const provincialRateTypes = [ ...response.data, rateTypeOther ]; + +// dispatch({ type: Action.UPDATE_PROVINCIAL_RATE_TYPES_LOOKUP, provincialRateTypes }); +// }; + +export const getOvertimeRateTypes = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/provincialratetypes/overtime').get()); + dispatch({ + type: Action.UPDATE_OVERTIME_RATE_TYPES_LOOKUP, + overtimeRateTypes: response.data, + }); +}; + +export const updateOvertimeRateType = (rate) => async (dispatch) => { + return await dispatch(new ApiRequest(`/provincialratetypes/${rate.id}`).put(rate)); +}; + +export const getRentalConditions = () => async (dispatch) => { + dispatch({ type: Action.RENTAL_CONDITIONS_LOOKUP_REQUEST }); + const response = await dispatch(new ApiRequest('/conditiontypes').get()); + dispatch({ + type: Action.UPDATE_RENTAL_CONDITIONS_LOOKUP, + rentalConditions: response.data, + }); +}; //////////////////// // Version //////////////////// -export function getVersion() { - return new ApiRequest('/version').get().then((response) => { - store.dispatch({ type: Action.UPDATE_VERSION, version: response }); - }); -} +export const getVersion = () => async (dispatch) => { + const response = await dispatch(new ApiRequest('/version').get()); + dispatch({ type: Action.UPDATE_VERSION, version: response }); +}; //////////////////// // Notes //////////////////// -export function deleteNote(id) { - store.dispatch({ type: Action.DELETE_NOTE, noteId: id }); - return new ApiRequest(`/notes/${id}/delete`).post().then((response) => { - return response.data; - }); -} +export const deleteNote = (id) => async (dispatch) => { + dispatch({ type: Action.DELETE_NOTE, noteId: id }); + const response = await dispatch(new ApiRequest(`/notes/${id}/delete`).post()); + return response.data; +}; -export function updateNote(note) { - return new ApiRequest(`/notes/${note.id}`).put(note).then((response) => { - return response.data; - }); -} +export const updateNote = (note) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/notes/${note.id}`).put(note)); + return response.data; +}; //////////////////// // Set User //////////////////// -export function setDevUser(user) { - return new ApiRequest(`/authentication/dev/token/${user}`).get().then((response) => { - return response; - }); -} +export const setDevUser = (user) => async (dispatch) => { + return await dispatch(new ApiRequest(`/authentication/dev/token/${user}`).get()); +}; //////////////////// // Time Records //////////////////// -export function deleteTimeRecord(timeRecordId) { - return new ApiRequest(`/timerecords/${timeRecordId}/delete`).post().then((response) => { - store.dispatch({ - type: Action.DELETE_TIME_RECORD, - timeRecord: response.data, - }); +export const deleteTimeRecord = (timeRecordId) => async (dispatch) => { + const response = await dispatch(new ApiRequest(`/timerecords/${timeRecordId}/delete`).post()); + dispatch({ + type: Action.DELETE_TIME_RECORD, + timeRecord: response.data, }); -} +}; diff --git a/client/src/js/components/Authorize.jsx b/client/src/js/components/Authorize.jsx index b684a3035..6eb307ba0 100644 --- a/client/src/js/components/Authorize.jsx +++ b/client/src/js/components/Authorize.jsx @@ -1,20 +1,19 @@ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import store from '../store'; //helper functions to use in other components -export const any = (...permissions) => { +export const any = (...permissions) => (_, getState) => { //returns true if user has any of the listed permissions. Equivelent to user has permission1 OR permission2. - const currentUserPermissions = store.getState().user.permissions; + const currentUserPermissions = getState().user.permissions; let result = permissions.some((permission) => currentUserPermissions?.includes(permission)); return result; }; -export const all = (...permissions) => { +export const all = (...permissions) => (_, getState) => { //returns true if user has all of the listed permissions. Equivelent to user has permission1 AND permission2. - const currentUserPermissions = store.getState().user.permissions; + const currentUserPermissions = getState().user.permissions; let result = permissions.every((permission) => currentUserPermissions?.includes(permission)); return result; }; @@ -30,11 +29,9 @@ const Authorize = ({ currentUser, requires, condition, children }) => { return children; }; -const mapStateToProps = (state) => { - return { - currentUser: state.user, - }; -}; +const mapStateToProps = (state) => ({ + currentUser: state.user, +}); Authorize.propTypes = { currentUser: PropTypes.object, @@ -43,4 +40,4 @@ Authorize.propTypes = { condition: PropTypes.bool, //allows for custom logic. Can use with 'any' or 'all' helper functions. ie. any('permission1', 'permission2') }; -export default connect(mapStateToProps, null)(Authorize); +export default connect(mapStateToProps)(Authorize); diff --git a/client/src/js/components/Authorize.test.jsx b/client/src/js/components/Authorize.test.jsx new file mode 100644 index 000000000..61bdbd8ec --- /dev/null +++ b/client/src/js/components/Authorize.test.jsx @@ -0,0 +1,106 @@ +import { screen } from "@testing-library/react"; + +import * as Constant from "../constants"; +import * as Action from "../actionTypes"; +import { getCurrentUser } from "../mock/api/getCurrentUser"; +import { renderWithProviders } from "../renderWithProviders"; +import { setupStore } from "../store"; +import Authorize from "./Authorize"; + +let store; + +beforeEach(() => { + store = setupStore(); +}) + +describe("show component when authorized", () => { + test("renders component given enough permissions", () => { + // Arrange + const authorizedStr = "authorized"; + const authorizedUser = getCurrentUser().data; + authorizedUser.hasPermission = (_) => true; + + store.dispatch({ + type: Action.UPDATE_CURRENT_USER, + user: authorizedUser, + }); + + // Act + renderWithProviders(( + +

{authorizedStr}

+
+ ), { store }); + + // Assert + expect(screen.getByText(authorizedStr)).toBeVisible(); + }); + + test("renders component when permissions not checked and condition is true", () => { + // Arrange + const authorizedStr = "authorized"; + const authorizedUser = getCurrentUser().data; + authorizedUser.hasPermission = (_) => false; + + store.dispatch({ + type: Action.UPDATE_CURRENT_USER, + user: authorizedUser, + }); + + // Act + renderWithProviders(( + +

{authorizedStr}

+
+ ), { store }); + + // Assert + expect(screen.getByText(authorizedStr)).toBeVisible(); + }); +}); + +describe("show nothing when unauthorized", () => { + test("renders nothing when user doesn't have permissions", () => { + // Arrange + const authorizedStr = "authorized"; + const authorizedUser = getCurrentUser().data; + authorizedUser.hasPermission = (_) => false; + + store.dispatch({ + type: Action.UPDATE_CURRENT_USER, + user: authorizedUser, + }); + + // Act + renderWithProviders(( + +

{authorizedStr}

+
+ ), { store }); + + // Assert + expect(screen.queryByText(authorizedStr)).toBeNull(); + }); + + test("renders nothing when permissions not checked and condition is false", () => { + // Arrange + const authorizedStr = "authorized"; + const authorizedUser = getCurrentUser().data; + authorizedUser.hasPermission = (_) => true; + + store.dispatch({ + type: Action.UPDATE_CURRENT_USER, + user: authorizedUser, + }); + + // Act + renderWithProviders(( + +

{authorizedStr}

+
+ ), { store }); + + // Assert + expect(screen.queryByText(authorizedStr)).toBeNull(); + }); +}); diff --git a/client/src/js/components/BadgeLabel.test.jsx b/client/src/js/components/BadgeLabel.test.jsx new file mode 100644 index 000000000..c5039bff3 --- /dev/null +++ b/client/src/js/components/BadgeLabel.test.jsx @@ -0,0 +1,17 @@ +import { render, screen } from "@testing-library/react"; +import BadgeLabel from "./BadgeLabel"; + +describe("BadgeLabel displays properly", () => { + test("BadgeLabel displays text properly", () => { + // Arrange + const text = "Test"; + + // Act + render(( + {text} + )); + + // Assert + expect(screen.getByText(text)).toBeVisible(); + }); +}); \ No newline at end of file diff --git a/client/src/js/components/CheckboxControl.test.jsx b/client/src/js/components/CheckboxControl.test.jsx new file mode 100644 index 000000000..1a2b84623 --- /dev/null +++ b/client/src/js/components/CheckboxControl.test.jsx @@ -0,0 +1,41 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import CheckboxControl from "./CheckboxControl"; + +const initialState = {}; + +let state; +let id; + +const updateState = (newState) => { + state = { ...newState }; +}; +const onChange = (e) => { + id = e.target.id; +}; + +beforeEach(() => { + state = { ...initialState }; + id = undefined; +}); + +describe("CheckboxControl updates correctly", () => { + test("CheckboxControl toggles state", () => { + // Arrange + const label = "Checkbox1"; + render(); + const input = screen.getByLabelText(label); + + // Act + fireEvent(input, new MouseEvent("click", { bubbles: true, cancelable: true })); + + // Assert + const expectedId = `checkboxControl-${label}`; + expect(id).toBe(expectedId); + expect(state[id]).toBe(true); + + fireEvent(input, new MouseEvent("click", { bubbles: true, cancelable: true })); + + expect(id).toBe(expectedId); + expect(state[id]).toBe(false); + }); +}); \ No newline at end of file diff --git a/client/src/js/components/ColDisplay.test.jsx b/client/src/js/components/ColDisplay.test.jsx new file mode 100644 index 000000000..6a80d0145 --- /dev/null +++ b/client/src/js/components/ColDisplay.test.jsx @@ -0,0 +1,19 @@ +import { render, screen } from "@testing-library/react"; +import ColDisplay from "./ColDisplay"; + +describe("ColDisplay displays properly", () => { + test("ColDisplay display label and text properly", () => { + // Arrange + const label = "Test Label"; + const text = "Test text"; + + // Act + render(( + {text} + )); + + // Assert + expect(screen.getByText(label)).toBeVisible(); + expect(screen.getByText(text)).toBeVisible(); + }); +}); \ No newline at end of file diff --git a/client/src/js/components/Confirm.test.jsx b/client/src/js/components/Confirm.test.jsx new file mode 100644 index 000000000..4f12ee63f --- /dev/null +++ b/client/src/js/components/Confirm.test.jsx @@ -0,0 +1,47 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import Confirm from "./Confirm"; + +let hasConfirmed; +let hasCancelled; + +const onConfirm = () => { + hasConfirmed = true; +}; + +const onCancel = () => { + hasCancelled = true; +}; + +beforeEach(() => { + hasConfirmed = false; + hasCancelled = false; +}); + +describe("Confirm performs correct actions", () => { + test("Confirm executes onConfirm properly", () => { + // Arrange + render(( + + )); + + // Act + fireEvent(screen.getByText("Yes"), new MouseEvent("click", { bubbles: true, cancelable: true })); + + // Assert + expect(hasConfirmed).toBe(true); + expect(hasCancelled).toBe(false); + }); + + test("Confirm executes onCancel properly", () => { + // Arrange + render(( + + )); + + fireEvent(screen.getByText("No"), new MouseEvent("click", { bubbles: true, cancelable: true })); + + // Assert + expect(hasConfirmed).toBe(false); + expect(hasCancelled).toBe(true); + }); +}); diff --git a/client/src/js/components/Countdown.jsx b/client/src/js/components/Countdown.jsx index 5cdc7b65c..1a6d5a88d 100644 --- a/client/src/js/components/Countdown.jsx +++ b/client/src/js/components/Countdown.jsx @@ -28,19 +28,19 @@ class Countdown extends React.Component { } startTimer = () => { - var timeLeft = this.state.timeLeft; - var interval = setInterval(function () { - var minutes = parseInt(timeLeft / 60, 10); - var seconds = parseInt(timeLeft % 60, 10); + let interval = setInterval(function () { + let timeLeft = this.state.timeLeft - 1; + let minutes = parseInt(timeLeft / 60, 10); + let seconds = parseInt(timeLeft % 60, 10); seconds = seconds < 10 ? '0' + seconds : seconds; - this.setState({ minutes, seconds }); - - if (--timeLeft < 0 && !this.state.fired) { - this.props.onEnd(); - this.setState({ fired: true }); - } + this.setState({ timeLeft, minutes, seconds }, () => { + if (timeLeft < 0 && !this.state.fired) { + this.props.onEnd(); + this.setState({ fired: true }); + } + }); }.bind(this), 1000); this.setState({ interval }); }; diff --git a/client/src/js/components/Countdown.test.jsx b/client/src/js/components/Countdown.test.jsx new file mode 100644 index 000000000..76ce2e735 --- /dev/null +++ b/client/src/js/components/Countdown.test.jsx @@ -0,0 +1,69 @@ +import { render, screen } from "@testing-library/react"; +import Countdown from "./Countdown"; + +describe("Countdown component display", () => { + test("Countdown correctly displays time greater than 1min", () => { + // Arrange + const time = 61; + + // Act + render(); + + // Assert + expect(screen.getByText("1m 01s")).toBeVisible(); + }); + + test("Countdown correctly displays time less than 1min", () => { + // Arrange + const time = 59; + + // Act + render(); + + // Assert + expect(screen.getByText("59s")).toBeVisible(); + }); + + test("Countdown correctly displays time less than 10sec", () => { + // Arrange + const time = 9; + + // Act + render(); + + // Assert + expect(screen.getByText("09s")).toBeVisible(); + }); +}); + +describe("Countdown component counting down", () => { + test("Countdown counts down correctly", () => { + // Arrange + jest.useFakeTimers(); + render(); + + expect(screen.getByText("05s")).toBeVisible(); + + // Act + jest.advanceTimersToNextTimer(2); + + // Assert + expect(screen.getByText("03s")).toBeVisible(); + }); + + test("Countdown executes callback when countdown finishes", () => { + // Arrange + jest.useFakeTimers(); + let finished = false; + const onEnd = () => { + finished = true; + }; + render(); + + // Act + jest.advanceTimersToNextTimer(2); + + // Assert + expect(finished).toBe(true); + }); +}); diff --git a/client/src/js/components/DateControl.test.jsx b/client/src/js/components/DateControl.test.jsx new file mode 100644 index 000000000..8c6cae03b --- /dev/null +++ b/client/src/js/components/DateControl.test.jsx @@ -0,0 +1,116 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import DateControl from "./DateControl"; + +const mockConsoleLog = jest.spyOn(console, "log"); +mockConsoleLog.mockImplementation(() => {}); + +describe("DateControl component display", () => { + test("DateControl displays correct date and format", () => { + // Arrange + const format = "YYYY-MM-DD"; + const dateStr = "2023-01-01"; + + // Act + render(( + + )); + + // Assert + expect(screen.getByDisplayValue(dateStr)).toBeVisible(); + }); +}); + +describe("DateControl component updating dates", () => { + test("DateControl updates date correctly", async () => { + // Arrange + const format = "YYYY-MM-DD"; + const dateStr = "2023-01-01"; + const id = "testdate"; + let currDateStr = dateStr; + let currId = id; + const onChange = (newDateStr, componentId) => { + currDateStr = newDateStr; + currId = componentId; + }; + const updateState = (state) => { + currDateStr = state[id]; + }; + const updatedDateStr = "2023-01-02"; + + render(( + + )); + + const dateInput = screen.getByDisplayValue(currDateStr); + + // Act + fireEvent.change(dateInput, { target: { value: updatedDateStr } }); + + // Assert + expect(currDateStr).toEqual(updatedDateStr); + }); + + test("DateControl date selection works correctly", async () => { + const user = userEvent.setup(); + + // Arrange + const format = "YYYY-MM-DD"; + const dateStr = "2022-01-01"; + const id = "testdate"; + let currDateStr = dateStr; + let currId = id; + const onChange = (newDateStr, componentId) => { + currDateStr = newDateStr; + currId = componentId; + }; + const updateState = (state) => { + currDateStr = state[id]; + }; + const updatedDateStr = "2023-03-02"; + + render(( + + )); + + const dateInput = screen.getByDisplayValue(currDateStr); + + // Act + await user.click(dateInput); + const monthYearSel = await screen.findByText("January 2022"); + await user.click(monthYearSel); + const yearSel = await screen.findByText("2022"); + await user.click(yearSel); + const yearEl = await screen.findByText("2023"); + await user.click(yearEl); + const monthEl = await screen.findByText("Mar"); + await user.click(monthEl); + const dayEl = await screen.findAllByText("2"); + await user.click(dayEl[0]); + + // Assert + expect(currDateStr).toEqual(updatedDateStr); + }); +}); diff --git a/client/src/js/components/DeleteButton.test.jsx b/client/src/js/components/DeleteButton.test.jsx new file mode 100644 index 000000000..6c540ad48 --- /dev/null +++ b/client/src/js/components/DeleteButton.test.jsx @@ -0,0 +1,124 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import DeleteButton from "./DeleteButton"; + +describe("DeleteButton display", () => { + test("DeleteButton displays normally", () => { + // Arrange and Act + render(( + {}} + /> + )); + + const deleteButtonEl = screen.getByTitle("Delete Test"); + + // Assert + expect(deleteButtonEl).not.toHaveClass("d-none"); + }); + + test("DeleteButton does not show when hidden", () => { + // Arrange and Act + render(( + {}} + /> + )); + + const deleteButtonEl = screen.getByTitle("Delete Test"); + + // Assert + expect(deleteButtonEl).toHaveClass("d-none"); + }); +}); + +describe("DeleteButton behaviour", () => { + test("DeleteButton onConfirm works properly", async () => { + const user = userEvent.setup(); + + // Arrange + let confirmDelete = false; + const onConfirm = () => { + confirmDelete = true; + }; + + render(( + + )); + + const deleteButtonEl = screen.getByTitle("Delete Test"); + + // Act + await user.click(deleteButtonEl); + expect(screen.getByText("Yes")).toBeInTheDocument(); + expect(screen.getByText("No")).toBeInTheDocument(); + const confirmYesButtonEl = await screen.findByText("Yes"); + await user.click(confirmYesButtonEl); + + // Assert + expect(confirmDelete).toBe(true); + }); + + test("DeleteButton onCancel works properly", async () => { + const user = userEvent.setup(); + + // Arrange + let confirmDelete = false; + const onConfirm = () => { + confirmDelete = true; + }; + + render(( + + )); + + const deleteButtonEl = screen.getByTitle("Delete Test"); + + // Act + await user.click(deleteButtonEl); + expect(screen.getByText("Yes")).toBeInTheDocument(); + expect(screen.getByText("No")).toBeInTheDocument(); + const confirmNoButtonEl = await screen.findByText("No"); + await user.click(confirmNoButtonEl); + + // Assert + expect(confirmDelete).toBe(false); + }); + + test("DeleteButton does not do anything when disabled", async () => { + const user = userEvent.setup(); + + // Arrange + let confirmDelete = false; + const onConfirm = () => { + confirmDelete = true; + }; + + render(( + + )); + + const deleteButtonEl = screen.getByTitle("Delete Test"); + + // Act + await user.click(deleteButtonEl); + + // Assert + expect(screen.queryByText("Yes")).toBeNull(); + expect(screen.queryByText("No")).toBeNull(); + expect(confirmDelete).toBe(false); + }); +}); \ No newline at end of file diff --git a/client/src/js/components/DropdownControl.test.jsx b/client/src/js/components/DropdownControl.test.jsx new file mode 100644 index 000000000..2a99caa8e --- /dev/null +++ b/client/src/js/components/DropdownControl.test.jsx @@ -0,0 +1,101 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import DropdownControl from "./DropdownControl"; + +describe("DropdownControl display", () => { + test("DropdownControl displays selected item properly", () => { + // Arrange and Act + const dropdownId = "dropdown"; + const items = [ + { id: 1, itemName: "Item 1" }, + { id: 2, itemName: "Item 2" }, + { id: 3, itemName: "Item 3" }, + ]; + let selectedItem = items[0]; + + render(( + + )); + + // Assert + expect(screen.queryAllByText(/Item [0-9]+/i)).toHaveLength(1); + expect(screen.queryAllByText(selectedItem.itemName)).toHaveLength(1); + }); + + test("DropdownControl displays list of selections", async () => { + const user = userEvent.setup(); + + // Arrange + const dropdownId = "dropdown"; + const items = [ + { id: 1, itemName: "Item 1" }, + { id: 2, itemName: "Item 2" }, + { id: 3, itemName: "Item 3" }, + ]; + render(( + + )); + + expect(screen.queryAllByText(/Item [0-9]+/i)).toHaveLength(0); + const dropdownEl = screen.getByText("Select item"); + + // Act + await user.click(dropdownEl); + + // Assert + expect(screen.queryAllByText(/Item [0-9]+/i)).toHaveLength(items.length); + }); +}); + +describe("DropdownControl behaviour", () => { + test("DropdownControl properly selects options", async () => { + const user = userEvent.setup(); + + // Arrange + const dropdownId = "dropdown"; + const items = [ + { id: 1, itemName: "Item 1" }, + { id: 2, itemName: "Item 2" }, + { id: 3, itemName: "Item 3" }, + ]; + let selectedItem = items[0]; + const updateState = (newItem) => { + const selectedId = newItem[dropdownId]; + const item = items.find(item => item.id === selectedId) ?? { itemName: "Not found" }; + selectedItem = { + id: selectedId, + itemName: item.itemName, + }; + }; + const updatedItem = items[1]; + + render(( + + )); + + const dropdownEl = screen.getByText(selectedItem.itemName); + + // Act + await user.click(dropdownEl); + await user.click(screen.getByText(updatedItem.itemName)); + + // Assert + expect(selectedItem).toEqual(updatedItem); + expect(screen.queryAllByText(/Item [0-9]+/i)[0]).toHaveTextContent(updatedItem.itemName); + }); +}); diff --git a/client/src/js/components/EditButton.test.jsx b/client/src/js/components/EditButton.test.jsx new file mode 100644 index 000000000..67d17326f --- /dev/null +++ b/client/src/js/components/EditButton.test.jsx @@ -0,0 +1,88 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import EditButton from "./EditButton"; + +describe("EditButton display", () => { + test("EditButton displays properly for view", () => { + // Arrange and Act + render(( + {}} + /> + )); + + const expectedText = "View Test"; + + // Assert + expect(screen.queryAllByTitle(expectedText)).toHaveLength(1); + const buttonEl = screen.getByTitle(expectedText); + expect(buttonEl).not.toHaveClass("d-none"); + }); + + test("EditButton displays properly for edit", () => { + // Arrange and Act + render(( + {}} + /> + )); + + const expectedText = "Edit Test"; + + // Assert + expect(screen.queryAllByTitle(expectedText)).toHaveLength(1); + const buttonEl = screen.getByTitle(expectedText); + expect(buttonEl).not.toHaveClass("d-none"); + }); + + test("EditButton properly hides button", () => { + // Arrange and Act + render(( + {}} + /> + )); + + const expectedText = "Edit Test"; + + // Assert + const buttonEl = screen.getByTitle(expectedText); + expect(buttonEl).toHaveClass("d-none"); + }); +}); + +describe("EditButton behaviour", () => { + test("EditButton onClick works properly", async () => { + const user = userEvent.setup(); + + // Arrange + let clicked = false; + const onClick = () => { + clicked = true; + }; + + render(( + + )); + + // Act + await user.click(screen.getByTitle("Edit Test")); + + // Assert + expect(clicked).toBe(true); + }); +}); diff --git a/client/src/js/components/ErrorBoundary.test.jsx b/client/src/js/components/ErrorBoundary.test.jsx new file mode 100644 index 000000000..f58def1cc --- /dev/null +++ b/client/src/js/components/ErrorBoundary.test.jsx @@ -0,0 +1,27 @@ +import { render, screen } from "@testing-library/react"; +import ErrorBoundary from "./ErrorBoundary"; + +const mockedConsoleLog = jest.spyOn(console, "log"); +mockedConsoleLog.mockImplementation(() => {}); + +const mockedConsoleError = jest.spyOn(console, "error"); +mockedConsoleError.mockImplementation(() => {}); + +const TestComponent = () => { + throw new Error("Test Error"); +}; + +describe("ErrorBoundary capture", () => { + test("ErrorBoundary captures child components errors", () => { + // Arrange and Act + render(( + + + + )); + + // Assert + expect(screen.queryAllByText(/something went wrong/i)).toHaveLength(1); + expect(mockedConsoleLog).toHaveBeenCalledWith("error captured"); + }); +}); \ No newline at end of file diff --git a/client/src/js/components/Favourites.jsx b/client/src/js/components/Favourites.jsx index c98c4b543..77ee57f98 100644 --- a/client/src/js/components/Favourites.jsx +++ b/client/src/js/components/Favourites.jsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { Alert, Dropdown, ButtonGroup, Button } from 'react-bootstrap'; -import { FormGroup, FormText, FormLabel } from 'react-bootstrap'; import { Col, Row } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import _ from 'lodash'; @@ -9,113 +9,10 @@ import _ from 'lodash'; import * as Api from '../api'; import * as Constant from '../constants'; -import CheckboxControl from '../components/CheckboxControl.jsx'; import DeleteButton from '../components/DeleteButton.jsx'; import EditButton from '../components/EditButton.jsx'; -import FormDialog from '../components/FormDialog.jsx'; -import FormInputControl from '../components/FormInputControl.jsx'; import Authorize from '../components/Authorize.jsx'; - -import { isBlank } from '../utils/string'; - -class EditFavouritesDialog extends React.Component { - static propTypes = { - favourite: PropTypes.object.isRequired, - onSave: PropTypes.func.isRequired, - onClose: PropTypes.func.isRequired, - show: PropTypes.bool, - }; - - constructor(props) { - super(props); - - this.state = { - isSaving: false, - name: props.favourite.name || '', - isDefault: props.favourite.isDefault || false, - nameError: '', - }; - } - - updateState = (state, callback) => { - this.setState(state, callback); - }; - - didChange = () => { - if (this.state.name !== this.props.favourite.name) { - return true; - } - if (this.state.isDefault !== this.props.favourite.isDefault) { - return true; - } - - return false; - }; - - isValid = () => { - if (isBlank(this.state.name)) { - this.setState({ nameError: 'Name is required' }); - return false; - } - return true; - }; - - onSubmit = () => { - if (this.isValid()) { - if (this.didChange()) { - this.setState({ isSaving: true }); - - const favourite = { - ...this.props.favourite, - name: this.state.name, - isDefault: this.state.isDefault, - }; - - const promise = favourite.id ? Api.updateFavourite(favourite) : Api.addFavourite(favourite); - promise.finally(() => { - this.setState({ isSaving: false }); - }); - - this.props.onSave(favourite); - } - - this.props.onClose(); - } - }; - - render() { - const { isSaving, name, nameError, isDefault } = this.state; - const { show, onClose } = this.props; - - return ( - - - - Name * - - - {nameError} - - - - ); - } -} +import EditFavouritesDialog from '../views/dialogs/EditFavouritesDialog'; class Favourites extends React.Component { static propTypes = { @@ -157,10 +54,10 @@ class Favourites extends React.Component { if (favourite.isDefault) { var oldDefault = _.find(this.props.favourites, (f) => f.isDefault); if (oldDefault && favourite.id !== oldDefault.id) { - Api.updateFavourite({ + this.props.dispatch(Api.updateFavourite({ ...oldDefault, isDefault: false, - }); + })); } } @@ -168,7 +65,7 @@ class Favourites extends React.Component { }; deleteFavourite = (favourite) => { - Api.deleteFavourite(favourite); + this.props.dispatch(Api.deleteFavourite(favourite)); }; selectFavourite = (favourite) => { @@ -251,4 +148,6 @@ class Favourites extends React.Component { } } -export default Favourites; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(Favourites); diff --git a/client/src/js/components/Favourites.test.jsx b/client/src/js/components/Favourites.test.jsx new file mode 100644 index 000000000..dc0ad0dae --- /dev/null +++ b/client/src/js/components/Favourites.test.jsx @@ -0,0 +1,277 @@ +import { setupServer } from "msw/lib/node"; +import { rest } from "msw"; + +import { keycloak } from "../Keycloak"; +import { setupStore } from "../store"; +import * as Action from "../actionTypes"; +import { getCurrentUser } from "../mock/api/getCurrentUser"; +import { renderWithProviders } from "../renderWithProviders"; +import Favourites from "./Favourites"; +import { getFavourites } from "../mock/api/getFavourites"; +import { screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; + +// Mock Keycloak service +const mockKeycloakUpdateToken = jest.spyOn(keycloak, "updateToken"); +mockKeycloakUpdateToken.mockResolvedValue(Promise.resolve(false)); + +const server = setupServer( + rest.post("/api/users/current/favourites/:favouriteId/delete", async (req, res, ctx) => { + const id = Number(req.params.favouriteId); + const fav = Object.values(getFavourites().customFav).find(f => f.id === id); + if (!fav) { + return res(ctx.status(404)); + } + return res(ctx.json({ + data: fav, + })); + }), + rest.post("/api/users/current/favourites", async (req, res, ctx) => { + const reqBody = await req.json(); + const favName = reqBody.name; + const resFav = Object.values(getFavourites().customFav).find(f => f.name === favName); + if (!resFav) { + return res(ctx.status(404)); + } + return res(ctx.json({ + data: resFav, + })); + }), + rest.put("/api/users/current/favourites", async (req, res, ctx) => { + const reqBody = await req.json(); + const { id, name, isDefault } = reqBody; + const fav = Object.values(getFavourites().customFav).find(f => f.id === id); + if (!fav) { + return res(ctx.status(404)); + } + + const resFav = { + ...fav, + name, + isDefault, + }; + return res(ctx.json({ + data: resFav, + })); + }), +); + +let store; + +beforeAll(() => { + server.listen(); +}); + +beforeEach(() => { + store = setupStore(); + + const authorizedUser = getCurrentUser().data; + authorizedUser.hasPermission = (_) => true; + + store.dispatch({ + type: Action.UPDATE_CURRENT_USER, + user: authorizedUser, + }); +}) + +afterEach(() => { + server.resetHandlers(); +}); + +afterAll(() => { + server.close(); +}); + +const setup = (component, store) => ({ + user: userEvent.setup(), + ...renderWithProviders(component, { store }), +}); + +describe("Favourites component", () => { + test("Favourites show empty favourites list properly", async () => { + const favourites = {}; + let searchParams = {}; + const onSelect = (favourite) => { + searchParams = JSON.parse(favourite.value); + }; + + const { user } = setup(( + + ), store); + + const favButton = await screen.findByText("Favourites"); + await user.click(favButton); + + const displayedFavEls = screen.queryAllByText(/Custom Fav \d+/i); + expect(displayedFavEls).toHaveLength(0); + }); + + test("Favourites show multiple favourites properly", async () => { + const favourites = getFavourites().customFav; + let searchParams = {}; + const onSelect = (favourite) => { + searchParams = JSON.parse(favourite.value); + }; + + const { user } = setup(( + + ), store); + + const favButton = await screen.findByText("Favourites"); + await user.click(favButton); + + const displayedFavEls = await screen.findAllByText(/Custom Fav \d+/i); + expect(displayedFavEls).toHaveLength(3); + }); + + test("Favourites can be selected properly", async () => { + const favourites = getFavourites().customFav; + let searchParams = {}; + const onSelect = (favourite) => { + searchParams = JSON.parse(favourite.value); + }; + + const { user } = setup(( + + ), store); + + const favButton = await screen.findByText("Favourites"); + await user.click(favButton); + const displayedFavEls = await screen.findAllByText(/Custom Fav \d+/i); + await user.click(displayedFavEls[0]); + + expect(searchParams).toEqual(JSON.parse(favourites[1].value)); + }); + + test("Favourites can be added successfully", async () => { + const sampleFavourite = getFavourites().customFav[1]; + const favourites = {}; + let searchParams = JSON.parse(sampleFavourite.value); + const onSelect = (favourite) => { + searchParams = JSON.parse(favourite.value); + }; + + const { user } = setup(( + + ), store); + + const favButton = await screen.findByText("Favourites"); + await user.click(favButton); + const addFavButton = await screen.findByText("Favourite Current Selection"); + await user.click(addFavButton); + const favNameTextField = await screen.findByLabelText(/Name/i); + await user.type(favNameTextField, sampleFavourite.name); + const saveButton = await screen.findByText("Save"); + await user.click(saveButton); + await waitFor(() => { + expect(store.getState().models.favourites.customFav).toEqual({ 1: sampleFavourite }); + }); + }); + + test("Favourites can be edited successfully", async () => { + const sampleFavourite = getFavourites().customFav[1]; + const favourites = { [sampleFavourite.id]: sampleFavourite }; + let searchParams = { customSearchParam: "Custom Search Arg" }; + const onSelect = (favourite) => { + searchParams = JSON.parse(favourite.value); + }; + + const newFavName = "New Fav Name"; + const newIsDefault = !sampleFavourite.isDefault; + + store.dispatch({ + type: Action.ADD_FAVOURITE, + favourite: sampleFavourite, + }); + + const { user } = setup(( + + ), store); + + expect(store.getState().models.favourites.customFav[1]).toEqual(sampleFavourite); + + const favButton = screen.getByText("Favourites"); + await user.click(favButton); + const editFavButton = screen.getByTitle("Edit Favourite"); + await user.click(editFavButton); + const favNameTextField = screen.getByLabelText(/Name/i); + await user.clear(favNameTextField); + await user.type(favNameTextField, newFavName, { initialSelectionStart: 0, initialSelectionEnd: sampleFavourite.name.length }); + const favDefaultCheckBox = screen.getByLabelText(/Default/i); + await user.click(favDefaultCheckBox); + const saveButton = screen.getByText("Save"); + await user.click(saveButton); + + // Edit should only change name and isDefault of favourite, not value + await waitFor(() => { + expect(store.getState().models.favourites.customFav[1].name).toBe(newFavName); + }); + expect(store.getState().models.favourites.customFav[1].isDefault).toBe(newIsDefault); + expect(store.getState().models.favourites.customFav[1].value).toBe(sampleFavourite.value); // value should stay the same + }); + + test("Favourites can be deleted successfully", async () => { + const sampleFavourite = getFavourites().customFav[1]; + const favourites = { [sampleFavourite.id]: sampleFavourite }; + let searchParams = JSON.parse(sampleFavourite.value); + const onSelect = (favourite) => { + searchParams = JSON.parse(favourite.value); + }; + + store.dispatch({ + type: Action.ADD_FAVOURITE, + favourite: sampleFavourite, + }); + + const { user } = setup(( + + ), store); + + const favButton = screen.getByText("Favourites"); + await user.click(favButton); + const deleteFavButton = screen.getByTitle("Delete Favourite"); + await user.click(deleteFavButton); + const confirmDeleteButton = screen.getByText(/Yes/i); + await user.click(confirmDeleteButton); + + await waitFor(() => { + expect(store.getState().models.favourites.customFav).toEqual({}); + }); + }); +}); \ No newline at end of file diff --git a/client/src/js/components/FilePicker.test.jsx b/client/src/js/components/FilePicker.test.jsx new file mode 100644 index 000000000..8218dcf6f --- /dev/null +++ b/client/src/js/components/FilePicker.test.jsx @@ -0,0 +1,40 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import FilePicker from "./FilePicker"; + +describe("FilePicker file selection", () => { + test("FilePicker selects file properly", async () => { + const user = userEvent.setup(); + + // Arrange + const expectedFiles = [ + new File(["test1"], "test1.png", { type: "image/png" }), + new File(["test2"], "test2.png", { type: "image/png" }), + new File(["test3"], "test3.png", { type: "image/png" }), + ]; + const selectedFiles = []; + const onFilesSelected = (files) => { + selectedFiles.push.apply(selectedFiles, files); + }; + + render(( + + )); + + const pickerEl = screen.getByLabelText(/File Picker/i); + + // Act + await user.upload(pickerEl, expectedFiles); + + // Assert + expect(selectedFiles).toHaveLength(expectedFiles.length); + expect(selectedFiles[0]).toStrictEqual(expectedFiles[0]); + expect(selectedFiles[1]).toStrictEqual(expectedFiles[1]); + expect(selectedFiles[2]).toStrictEqual(expectedFiles[2]); + }); +}); \ No newline at end of file diff --git a/client/src/js/components/FileUpload.jsx b/client/src/js/components/FileUpload.jsx index 9298d9ab7..53439810f 100644 --- a/client/src/js/components/FileUpload.jsx +++ b/client/src/js/components/FileUpload.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { Button, OverlayTrigger, Tooltip, ProgressBar } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -31,14 +32,15 @@ class FileUpload extends React.Component { }; } - uploadFiles = () => { + uploadFiles = async () => { + const dispatch = this.props.dispatch; this.setState({ uploadInProgress: true, percentUploaded: 0 }); - var options = { + const options = { method: 'POST', files: this.props.files, onUploadProgress: (percentComplete) => { - var percent = Math.round(percentComplete); + const percent = Math.round(percentComplete); this.setState({ percentUploaded: percent }); if (this.props.onUploadProgress) { this.props.onUploadProgress(percent); @@ -46,20 +48,18 @@ class FileUpload extends React.Component { }, }; - this.uploadPromise = request(buildApiPath(this.props.path || FILE_UPLOAD_PATH), options).then( - () => { - this.setState({ uploadInProgress: false, percentUploaded: null }); - if (this.props.onUploadFinished) { - this.props.onUploadFinished(true); - } - }, - (err) => { - this.setState({ uploadInProgress: false, fileUploadError: err }); - if (this.props.onUploadFinished) { - this.props.onUploadFinished(err); - } + try { + this.uploadPromise = await dispatch(request(buildApiPath(this.props.path || FILE_UPLOAD_PATH), options)); + this.setState({ uploadInProgress: false, percentUploaded: null }); + if (this.props.onUploadFinished) { + this.props.onUploadFinished(true); } - ); + } catch (err) { + this.setState({ uploadInProgress: false, fileUploadError: err }); + if (this.props.onUploadFinished) { + this.props.onUploadFinished(err); + } + } }; reset = () => { @@ -101,7 +101,7 @@ class FileUpload extends React.Component { ); } else { uploadProgressBar = ( - + ); } } else { @@ -128,4 +128,6 @@ class FileUpload extends React.Component { } } -export default FileUpload; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(FileUpload); diff --git a/client/src/js/components/History.jsx b/client/src/js/components/History.jsx index b129c447f..d783237df 100644 --- a/client/src/js/components/History.jsx +++ b/client/src/js/components/History.jsx @@ -8,7 +8,6 @@ import _ from 'lodash'; import * as Action from '../actionTypes'; import * as Constant from '../constants'; import * as History from '../history'; -import store from '../store'; import SortTable from './SortTable.jsx'; import Spinner from './Spinner.jsx'; @@ -58,7 +57,7 @@ class HistoryComponent extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_HISTORY_UI, history: this.state.ui }); + this.props.dispatch({ type: Action.UPDATE_HISTORY_UI, history: this.state.ui }); if (callback) { callback(); } @@ -79,12 +78,13 @@ class HistoryComponent extends React.Component { } } - return History.get(this.props.historyEntity, 0, first ? API_LIMIT : null).finally(() => { - this.setState({ - loading: false, - canShowMore: first && Object.keys(this.props.history).length >= API_LIMIT, + return this.props.dispatch(History.get(this.props.historyEntity, 0, first ? API_LIMIT : null)) + .finally(() => { + this.setState({ + loading: false, + canShowMore: first && Object.keys(this.props.history).length >= API_LIMIT, + }); }); - }); }; showMore = () => { @@ -178,14 +178,13 @@ class HistoryComponent extends React.Component { const makeMapStateToProps = () => { const getHistorySelector = makeGetHistorySelector(); - const mapStateToProps = (state, props) => { - return { - history: getHistorySelector(state, props), - users: state.lookups.users, - ui: state.ui.history, - }; - }; - return mapStateToProps; + return (state, props) => ({ + history: getHistorySelector(state, props), + users: state.lookups.users, + ui: state.ui.history, + }); }; -export default connect(makeMapStateToProps)(HistoryComponent); +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(makeMapStateToProps, mapDispatchToProps)(HistoryComponent); diff --git a/client/src/js/components/MultiDropdown.jsx b/client/src/js/components/MultiDropdown.jsx index 15bdecfb7..b8646f06d 100644 --- a/client/src/js/components/MultiDropdown.jsx +++ b/client/src/js/components/MultiDropdown.jsx @@ -128,7 +128,11 @@ class MultiDropdown extends React.Component { this.setState({ open: open }, () => { if (this.myRef.current) { //without a delay focus will not shift to input box when using keyboard shortcuts. I think the focus is called before input is rendered. - setTimeout(() => this.myRef.current.focus(), 100); + setTimeout(() => { + if (this.myRef.current && this.myRef.current.focus) { + this.myRef.current.focus(); + } + }, 100); } }); }; diff --git a/client/src/js/history.js b/client/src/js/history.js index c4a80936a..fc7df0cba 100644 --- a/client/src/js/history.js +++ b/client/src/js/history.js @@ -67,12 +67,12 @@ export function makeHistoryEntity(type, entity) { } // Log a history event -export function log(historyEntity, event, ...entities) { +export const log = (historyEntity, event, ...entities) => async (dispatch) => { // prepend the 'parent' entity entities.unshift(historyEntity); // Build the history text - var historyText = JSON.stringify({ + const historyText = JSON.stringify({ // The event text, with entity placeholders text: event, // The array of entities @@ -80,7 +80,7 @@ export function log(historyEntity, event, ...entities) { }); // Choose the correct API call. - var addHistoryPromise = null; + let addHistoryPromise = null; switch (historyEntity.type) { case Constant.HISTORY_OWNER: @@ -107,13 +107,11 @@ export function log(historyEntity, event, ...entities) { } if (addHistoryPromise) { - return addHistoryPromise(historyEntity.id, { - historyText: historyText, - }); + return await dispatch(addHistoryPromise(historyEntity.id, { historyText })); } return null; -} +}; function buildLink(entity, closeFunc) { // Return a link if the entity has a path; just the description otherwise. @@ -153,25 +151,25 @@ export function renderEvent(historyText, closeFunc) { } } -export function get(historyEntity, offset, limit) { +export const get = (historyEntity, offset, limit) => async (dispatch) => { // If not showing all, then just fetch the first 10 entries - var params = { + const params = { offset: offset || 0, limit: limit || null, }; switch (historyEntity.type) { case Constant.HISTORY_OWNER: - return Api.getOwnerHistory(historyEntity.id, params); + return await dispatch(Api.getOwnerHistory(historyEntity.id, params)); case Constant.HISTORY_PROJECT: - return Api.getProjectHistory(historyEntity.id, params); + return await dispatch(Api.getProjectHistory(historyEntity.id, params)); case Constant.HISTORY_EQUIPMENT: - return Api.getEquipmentHistory(historyEntity.id, params); + return await dispatch(Api.getEquipmentHistory(historyEntity.id, params)); case Constant.HISTORY_REQUEST: - return Api.getRentalRequestHistory(historyEntity.id, params); + return await dispatch(Api.getRentalRequestHistory(historyEntity.id, params)); case Constant.HISTORY_USER: case Constant.HISTORY_ROLE: @@ -181,184 +179,184 @@ export function get(historyEntity, offset, limit) { } return null; -} +}; // Logging -export function ownerAdded(owner) { - return log(owner.historyEntity, OWNER_ADDED); -} +export const ownerAdded = (owner) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_ADDED)); +}; -export function ownerModified(owner) { - return log(owner.historyEntity, OWNER_MODIFIED); -} +export const ownerModified = (owner) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_MODIFIED)); +}; -export function ownerModifiedStatus(owner, status, statusComment) { - return log(owner.historyEntity, OWNER_MODIFIED_STATUS, { description: status }, { description: statusComment }); -} +export const ownerModifiedStatus = (owner, status, statusComment) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_MODIFIED_STATUS, { description: status }, { description: statusComment })); +}; -export function ownerContactAdded(owner, contact) { - return log(owner.historyEntity, OWNER_CONTACT_ADDED, contact.historyEntity); -} +export const ownerContactAdded = (owner, contact) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_CONTACT_ADDED, contact.historyEntity)); +}; -export function ownerContactUpdated(owner, contact) { - return log(owner.historyEntity, OWNER_CONTACT_UPDATED, contact.historyEntity); -} +export const ownerContactUpdated = (owner, contact) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_CONTACT_UPDATED, contact.historyEntity)); +}; -export function ownerContactDeleted(owner, contact) { - return log(owner.historyEntity, OWNER_CONTACT_DELETED, contact.historyEntity); -} +export const ownerContactDeleted = (owner, contact) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_CONTACT_DELETED, contact.historyEntity)); +}; -export function ownerModifiedPolicy(owner) { - return log(owner.historyEntity, OWNER_MODIFIED_POLICY); -} +export const ownerModifiedPolicy = (owner) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_MODIFIED_POLICY)); +}; -export function ownerEquipmentAdded(owner, equipment) { - return log(owner.historyEntity, OWNER_EQUIPMENT_ADDED, equipment.historyEntity); -} +export const ownerEquipmentAdded = (owner, equipment) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_EQUIPMENT_ADDED, equipment.historyEntity)); +}; -export function ownerEquipmentVerified(owner, equipment) { - return log(owner.historyEntity, OWNER_EQUIPMENT_VERIFIED, equipment.historyEntity); -} +export const ownerEquipmentVerified = (owner, equipment) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_EQUIPMENT_VERIFIED, equipment.historyEntity)); +}; -export function ownerDocumentAdded(owner, document) { - return log(owner.historyEntity, OWNER_DOCUMENT_ADDED, { +export const ownerDocumentAdded = (owner, document) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_DOCUMENT_ADDED, { description: document, - }); -} + })); +}; -export function ownerDocumentsAdded(owner) { - return log(owner.historyEntity, OWNER_DOCUMENTS_ADDED); -} +export const ownerDocumentsAdded = (owner) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_DOCUMENTS_ADDED)); +}; -export function ownerDocumentDeleted(owner, document) { - return log(owner.historyEntity, OWNER_DOCUMENT_DELETED, document.historyEntity); -} +export const ownerDocumentDeleted = (owner, document) => async (dispatch) => { + return await dispatch(log(owner.historyEntity, OWNER_DOCUMENT_DELETED, document.historyEntity)); +}; -export function projectAdded(project) { - return log(project.historyEntity, PROJECT_ADDED); -} +export const projectAdded = (project) => async (dispatch) => { + return await dispatch(log(project.historyEntity, PROJECT_ADDED)); +}; -export function projectModified(project) { - return log(project.historyEntity, PROJECT_MODIFIED); -} +export const projectModified = (project) => async (dispatch) => { + return await dispatch(log(project.historyEntity, PROJECT_MODIFIED)); +}; -export function projectModifiedStatus(project) { - return log(project.historyEntity, PROJECT_MODIFIED_STATUS, { +export const projectModifiedStatus = (project) => async (dispatch) => { + return await dispatch(log(project.historyEntity, PROJECT_MODIFIED_STATUS, { description: project.status, - }); -} + })); +}; -export function projectContactAdded(project, contact) { - return log(project.historyEntity, PROJECT_CONTACT_ADDED, contact.historyEntity); -} +export const projectContactAdded = (project, contact) => async (dispatch) => { + return await dispatch(log(project.historyEntity, PROJECT_CONTACT_ADDED, contact.historyEntity)); +}; -export function projectContactUpdated(project, contact) { - return log(project.historyEntity, PROJECT_CONTACT_UPDATED, contact.historyEntity); -} +export const projectContactUpdated = (project, contact) => async (dispatch) => { + return await dispatch(log(project.historyEntity, PROJECT_CONTACT_UPDATED, contact.historyEntity)); +}; -export function projectContactDeleted(project, contact) { - return log(project.historyEntity, PROJECT_CONTACT_DELETED, contact.historyEntity); -} +export const projectContactDeleted = (project, contact) => async (dispatch) => { + return await dispatch(log(project.historyEntity, PROJECT_CONTACT_DELETED, contact.historyEntity)); +}; -export function projectDocumentAdded(project, document) { - return log(project.historyEntity, PROJECT_DOCUMENT_ADDED, { +export const projectDocumentAdded = (project, document) => async (dispatch) => { + return await dispatch(log(project.historyEntity, PROJECT_DOCUMENT_ADDED, { description: document, - }); -} + })); +}; -export function projectDocumentsAdded(project) { - return log(project.historyEntity, PROJECT_DOCUMENTS_ADDED); -} +export const projectDocumentsAdded = (project) => async (dispatch) => { + return await dispatch(log(project.historyEntity, PROJECT_DOCUMENTS_ADDED)); +}; -export function projectDocumentDeleted(project, document) { - return log(project.historyEntity, PROJECT_DOCUMENT_DELETED, document.historyEntity); -} +export const projectDocumentDeleted = (project, document) => async (dispatch) => { + return await dispatch(log(project.historyEntity, PROJECT_DOCUMENT_DELETED, document.historyEntity)); +}; -export function projectEquipmentReleased(project, equipment) { - return log(project.historyEntity, PROJECT_EQUIPMENT_RELEASED, equipment.historyEntity); -} +export const projectEquipmentReleased = (project, equipment) => async (dispatch) => { + return await dispatch(log(project.historyEntity, PROJECT_EQUIPMENT_RELEASED, equipment.historyEntity)); +}; -export function projectRentalRequestAdded(project, rentalRequest) { - return log(project.historyEntity, PROJECT_RENTAL_REQUEST_ADDED, rentalRequest.historyEntity); -} +export const projectRentalRequestAdded = (project, rentalRequest) => async (dispatch) => { + return await dispatch(log(project.historyEntity, PROJECT_RENTAL_REQUEST_ADDED, rentalRequest.historyEntity)); +}; -export function equipmentAdded(equipment) { - return log(equipment.historyEntity, EQUIPMENT_ADDED); -} +export const equipmentAdded = (equipment) => async (dispatch) => { + return await dispatch(log(equipment.historyEntity, EQUIPMENT_ADDED)); +}; -export function equipmentModified(equipment) { - return log(equipment.historyEntity, EQUIPMENT_MODIFIED); -} +export const equipmentModified = (equipment) => async (dispatch) => { + return await dispatch(log(equipment.historyEntity, EQUIPMENT_MODIFIED)); +}; -export function equipmentSeniorityModified(equipment) { - return log(equipment.historyEntity, EQUIPMENT_SENIORITY_MODIFIED); -} +export const equipmentSeniorityModified = (equipment) => async (dispatch) => { + return await dispatch(log(equipment.historyEntity, EQUIPMENT_SENIORITY_MODIFIED)); +}; -export function equipmentStatusModified(equipment, status, statusComment) { - return log( +export const equipmentStatusModified = (equipment, status, statusComment) => async (dispatch) => { + return await dispatch(log( equipment.historyEntity, EQUIPMENT_STATUS_MODIFIED, { description: status }, { description: statusComment } - ); -} + )); +}; -export function equipmentDocumentAdded(equipment, document) { - return log(equipment.historyEntity, EQUIPMENT_DOCUMENT_ADDED, { +export const equipmentDocumentAdded = (equipment, document) => async (dispatch) => { + return await dispatch(log(equipment.historyEntity, EQUIPMENT_DOCUMENT_ADDED, { description: document, - }); -} + })); +}; -export function equipmentDocumentsAdded(equipment) { - return log(equipment.historyEntity, EQUIPMENT_DOCUMENTS_ADDED); -} +export const equipmentDocumentsAdded = (equipment) => async (dispatch) => { + return await dispatch(log(equipment.historyEntity, EQUIPMENT_DOCUMENTS_ADDED)); +}; -export function equipmentDocumentDeleted(equipment, document) { - return log(equipment.historyEntity, EQUIPMENT_DOCUMENT_DELETED, document.historyEntity); -} +export const equipmentDocumentDeleted = (equipment, document) => async (dispatch) => { + return await dispatch(log(equipment.historyEntity, EQUIPMENT_DOCUMENT_DELETED, document.historyEntity)); +}; -export function equipmentAttachmentAdded(equipment, attachment) { - return log(equipment.historyEntity, EQUIPMENT_ATTACHMENT_ADDED, { +export const equipmentAttachmentAdded = (equipment, attachment) => async (dispatch) => { + return await dispatch(log(equipment.historyEntity, EQUIPMENT_ATTACHMENT_ADDED, { description: attachment, - }); -} + })); +}; -export function equipmentAttachmentUpdated(equipment, attachment) { - return log(equipment.historyEntity, EQUIPMENT_ATTACHMENT_UPDATED, { +export const equipmentAttachmentUpdated = (equipment, attachment) => async (dispatch) => { + return await dispatch(log(equipment.historyEntity, EQUIPMENT_ATTACHMENT_UPDATED, { description: attachment, - }); -} + })); +}; -export function equipmentAttachmentDeleted(equipment, attachment) { - return log(equipment.historyEntity, EQUIPMENT_ATTACHMENT_DELETED, { +export const equipmentAttachmentDeleted = (equipment, attachment) => async (dispatch) => { + return await dispatch(log(equipment.historyEntity, EQUIPMENT_ATTACHMENT_DELETED, { description: attachment, - }); -} + })); +}; -export function rentalRequestAdded(rentalRequest) { - return log(rentalRequest.historyEntity, RENTAL_REQUEST_ADDED); -} +export const rentalRequestAdded = (rentalRequest) => async (dispatch) => { + return await dispatch(log(rentalRequest.historyEntity, RENTAL_REQUEST_ADDED)); +}; -export function rentalRequestModified(rentalRequest) { - return log(rentalRequest.historyEntity, RENTAL_REQUEST_MODIFIED); -} +export const rentalRequestModified = (rentalRequest) => async (dispatch) => { + return await dispatch(log(rentalRequest.historyEntity, RENTAL_REQUEST_MODIFIED)); +}; -export function rentalRequestDocumentAdded(rentalRequest, document) { - return log(rentalRequest.historyEntity, RENTAL_REQUEST_DOCUMENT_ADDED, { +export const rentalRequestDocumentAdded = (rentalRequest, document) => async (dispatch) => { + return await dispatch(log(rentalRequest.historyEntity, RENTAL_REQUEST_DOCUMENT_ADDED, { description: document, - }); -} + })); +}; -export function rentalRequestDocumentsAdded(rentalRequest) { - return log(rentalRequest.historyEntity, RENTAL_REQUEST_DOCUMENTS_ADDED); -} +export const rentalRequestDocumentsAdded = (rentalRequest) => async (dispatch) => { + return await dispatch(log(rentalRequest.historyEntity, RENTAL_REQUEST_DOCUMENTS_ADDED)); +}; -export function rentalRequestDocumentDeleted(rentalRequest, document) { - return log(rentalRequest.historyEntity, RENTAL_REQUEST_DOCUMENT_DELETED, document.historyEntity); -} +export const rentalRequestDocumentDeleted = (rentalRequest, document) => async (dispatch) => { + return await dispatch(log(rentalRequest.historyEntity, RENTAL_REQUEST_DOCUMENT_DELETED, document.historyEntity)); +}; -export function rentalRequestEquipmentHired(rentalRequest, equipment, offerResponse) { - return log(rentalRequest.historyEntity, RENTAL_REQUEST_EQUIPMENT_HIRED, equipment.historyEntity, { +export const rentalRequestEquipmentHired = (rentalRequest, equipment, offerResponse) => async (dispatch) => { + return await dispatch(log(rentalRequest.historyEntity, RENTAL_REQUEST_EQUIPMENT_HIRED, equipment.historyEntity, { description: offerResponse, - }); -} + })); +}; diff --git a/client/src/js/mock/api/AitReport/getEquipmentTypes.js b/client/src/js/mock/api/AitReport/getEquipmentTypes.js new file mode 100644 index 000000000..a6e9c99a6 --- /dev/null +++ b/client/src/js/mock/api/AitReport/getEquipmentTypes.js @@ -0,0 +1,104 @@ +export const getEquipmentTypes = () => ({ + data: [ + { + id: 1214, + name: "Eq Type 1214", + agreementIds: [ + 815 + ], + projectIds: [ + 180 + ] + }, + { + id: 1227, + name: "Eq Type 1227", + agreementIds: [ + 799 + ], + projectIds: [ + 311 + ] + }, + { + id: 1198, + name: "Eq Type 1198", + agreementIds: [ + 699 + ], + projectIds: [ + 78 + ] + }, + { + id: 1228, + name: "Eq Type 1228", + agreementIds: [ + 698 + ], + projectIds: [ + 78 + ] + }, + { + id: 1212, + name: "Eq Type 1212", + agreementIds: [ + 695 + ], + projectIds: [ + 73 + ] + }, + { + id: 1225, + name: "Eq Type 1225", + agreementIds: [ + 684 + ], + projectIds: [ + 19 + ] + }, + { + id: 1185, + name: "Eq Type 1185", + agreementIds: [ + 673 + ], + projectIds: [ + 179 + ] + }, + { + id: 1209, + name: "Eq Type 1209", + agreementIds: [ + 622 + ], + projectIds: [ + 35 + ] + }, + { + id: 1186, + name: "Eq Type 1186", + agreementIds: [ + 616 + ], + projectIds: [ + 182 + ] + }, + { + id: 1210, + name: "Eq Type 1210", + agreementIds: [ + 611 + ], + projectIds: [ + 180 + ] + } + ], +}); diff --git a/client/src/js/mock/api/AitReport/getEquipments.js b/client/src/js/mock/api/AitReport/getEquipments.js new file mode 100644 index 000000000..5f3e5b608 --- /dev/null +++ b/client/src/js/mock/api/AitReport/getEquipments.js @@ -0,0 +1,576 @@ +export const getEquipments = () => ({ + data: [ + { + id: 15156, + equipmentCode: "EC15156", + agreementIds: [ + 609 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1209 + }, + { + id: 15205, + equipmentCode: "EC15205", + agreementIds: [ + 621 + ], + projectIds: [ + 35 + ], + districtEquipmentTypeId: 1209 + }, + { + id: 15216, + equipmentCode: "EC15216", + agreementIds: [ + 622 + ], + projectIds: [ + 35 + ], + districtEquipmentTypeId: 1209 + }, + { + id: 5845, + equipmentCode: "EC5845", + agreementIds: [ + 607 + ], + projectIds: [ + 19 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 6000, + equipmentCode: "EC6000", + agreementIds: [ + 606 + ], + projectIds: [ + 19 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 5988, + equipmentCode: "EC5988", + agreementIds: [ + 611 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1210 + }, + { + id: 25525, + equipmentCode: "EC25525", + agreementIds: [ + 673 + ], + projectIds: [ + 179 + ], + districtEquipmentTypeId: 1185 + }, + { + id: 15564, + equipmentCode: "EC15564", + agreementIds: [ + 612 + ], + projectIds: [ + 78 + ], + districtEquipmentTypeId: 1198 + }, + { + id: 18606, + equipmentCode: "EC18606", + agreementIds: [ + 614 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1198 + }, + { + id: 5786, + equipmentCode: "EC5786", + agreementIds: [ + 615 + ], + projectIds: [ + 182 + ], + districtEquipmentTypeId: 1186 + }, + { + id: 25524, + equipmentCode: "EC25524", + agreementIds: [ + 623 + ], + projectIds: [ + 179 + ], + districtEquipmentTypeId: 1185 + }, + { + id: 15474, + equipmentCode: "EC15474", + agreementIds: [ + 616 + ], + projectIds: [ + 182 + ], + districtEquipmentTypeId: 1186 + }, + { + id: 5909, + equipmentCode: "EC5909", + agreementIds: [ + 627 + ], + projectIds: [ + 179 + ], + districtEquipmentTypeId: 1225 + }, + { + id: 25525, + equipmentCode: "EC25525", + agreementIds: [ + 624 + ], + projectIds: [ + 179 + ], + districtEquipmentTypeId: 1185 + }, + { + id: 13623, + equipmentCode: "EC13623", + agreementIds: [ + 608 + ], + projectIds: [ + 19 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 7041, + equipmentCode: "EC7041", + agreementIds: [ + 683 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 9642, + equipmentCode: "EC9642", + agreementIds: [ + 637 + ], + projectIds: [ + 19 + ], + districtEquipmentTypeId: 1225 + }, + { + id: 5746, + equipmentCode: "EC5746", + agreementIds: [ + 674 + ], + projectIds: [ + 179 + ], + districtEquipmentTypeId: 1225 + }, + { + id: 5666, + equipmentCode: "EC5666", + agreementIds: [ + 636 + ], + projectIds: [ + 19 + ], + districtEquipmentTypeId: 1225 + }, + { + id: 6157, + equipmentCode: "EC6157", + agreementIds: [ + 689 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 6432, + equipmentCode: "EC6432", + agreementIds: [ + 685 + ], + projectIds: [ + 179 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 6164, + equipmentCode: "EC6164", + agreementIds: [ + 686 + ], + projectIds: [ + 179 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 10615, + equipmentCode: "EC10615", + agreementIds: [ + 691 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 6162, + equipmentCode: "EC6162", + agreementIds: [ + 687 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 6155, + equipmentCode: "EC6155", + agreementIds: [ + 690 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 6158, + equipmentCode: "EC6158", + agreementIds: [ + 688 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 9826, + equipmentCode: "EC9826", + agreementIds: [ + 692 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 6619, + equipmentCode: "EC6619", + agreementIds: [ + 695 + ], + projectIds: [ + 73 + ], + districtEquipmentTypeId: 1212 + }, + { + id: 18723, + equipmentCode: "EC18723", + agreementIds: [ + 694 + ], + projectIds: [ + 78 + ], + districtEquipmentTypeId: 1228 + }, + { + id: 6618, + equipmentCode: "EC6618", + agreementIds: [ + 696 + ], + projectIds: [ + 311 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 6238, + equipmentCode: "EC6238", + agreementIds: [ + 697 + ], + projectIds: [ + 62 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 22541, + equipmentCode: "EC22541", + agreementIds: [ + 698 + ], + projectIds: [ + 78 + ], + districtEquipmentTypeId: 1228 + }, + { + id: 15478, + equipmentCode: "EC15478", + agreementIds: [ + 699 + ], + projectIds: [ + 78 + ], + districtEquipmentTypeId: 1198 + }, + { + id: 6030, + equipmentCode: "EC6030", + agreementIds: [ + 684 + ], + projectIds: [ + 19 + ], + districtEquipmentTypeId: 1225 + }, + { + id: 12388, + equipmentCode: "EC12388", + agreementIds: [ + 799 + ], + projectIds: [ + 311 + ], + districtEquipmentTypeId: 1227 + }, + { + id: 25609, + equipmentCode: "EC25609", + agreementIds: [ + 801 + ], + projectIds: [ + 344 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25608, + equipmentCode: "EC25608", + agreementIds: [ + 800 + ], + projectIds: [ + 344 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25609, + equipmentCode: "EC25609", + agreementIds: [ + 802 + ], + projectIds: [ + 344 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25613, + equipmentCode: "EC25613", + agreementIds: [ + 803 + ], + projectIds: [ + 344 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25614, + equipmentCode: "EC25614", + agreementIds: [ + 804 + ], + projectIds: [ + 344 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25608, + equipmentCode: "EC25608", + agreementIds: [ + 805 + ], + projectIds: [ + 344 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25610, + equipmentCode: "EC25610", + agreementIds: [ + 807 + ], + projectIds: [ + 149 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25609, + equipmentCode: "EC25609", + agreementIds: [ + 806 + ], + projectIds: [ + 149 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25609, + equipmentCode: "EC25609", + agreementIds: [ + 809 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25610, + equipmentCode: "EC25610", + agreementIds: [ + 810 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25608, + equipmentCode: "EC25608", + agreementIds: [ + 812 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 10276, + equipmentCode: "EC10276", + agreementIds: [ + 693 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25610, + equipmentCode: "EC25610", + agreementIds: [ + 811 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25610, + equipmentCode: "EC25610", + agreementIds: [ + 813 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25609, + equipmentCode: "EC25609", + agreementIds: [ + 814 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 13623, + equipmentCode: "EC13623", + agreementIds: [ + 681 + ], + projectIds: [ + 19 + ], + districtEquipmentTypeId: 1214 + }, + { + id: 25609, + equipmentCode: "EC25609", + agreementIds: [ + 815 + ], + projectIds: [ + 180 + ], + districtEquipmentTypeId: 1214 + } + ], +}); diff --git a/client/src/js/mock/api/AitReport/getProjects.js b/client/src/js/mock/api/AitReport/getProjects.js new file mode 100644 index 000000000..cfe2356c4 --- /dev/null +++ b/client/src/js/mock/api/AitReport/getProjects.js @@ -0,0 +1,368 @@ +export const getProjects = () => ({ + data: [ + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 609 + ] + }, + { + id: 35, + name: "Test Project 35", + agreementIds: [ + 621 + ] + }, + { + id: 35, + name: "Test Project 35", + agreementIds: [ + 622 + ] + }, + { + id: 19, + name: "Test Project 19", + agreementIds: [ + 607 + ] + }, + { + id: 19, + name: "Test Project 19", + agreementIds: [ + 606 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 611 + ] + }, + { + id: 179, + name: "Test Project 179", + agreementIds: [ + 673 + ] + }, + { + id: 78, + name: "Test Project 78", + agreementIds: [ + 612 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 614 + ] + }, + { + id: 182, + name: "Test Project 182", + agreementIds: [ + 615 + ] + }, + { + id: 179, + name: "Test Project 179", + agreementIds: [ + 623 + ] + }, + { + id: 182, + name: "Test Project 182", + agreementIds: [ + 616 + ] + }, + { + id: 179, + name: "Test Project 179", + agreementIds: [ + 627 + ] + }, + { + id: 179, + name: "Test Project 179", + agreementIds: [ + 624 + ] + }, + { + id: 19, + name: "Test Project 19", + agreementIds: [ + 608 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 683 + ] + }, + { + id: 19, + name: "Test Project 19", + agreementIds: [ + 637 + ] + }, + { + id: 179, + name: "Test Project 179", + agreementIds: [ + 674 + ] + }, + { + id: 19, + name: "Test Project 19", + agreementIds: [ + 636 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 689 + ] + }, + { + id: 179, + name: "Test Project 179", + agreementIds: [ + 685 + ] + }, + { + id: 179, + name: "Test Project 179", + agreementIds: [ + 686 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 691 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 687 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 690 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 688 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 692 + ] + }, + { + id: 73, + name: "Test Project 73", + agreementIds: [ + 695 + ] + }, + { + id: 78, + name: "Test Project 78", + agreementIds: [ + 694 + ] + }, + { + id: 311, + name: "Test Project 311", + agreementIds: [ + 696 + ] + }, + { + id: 62, + name: "Test Project 62", + agreementIds: [ + 697 + ] + }, + { + id: 78, + name: "Test Project 78", + agreementIds: [ + 698 + ] + }, + { + id: 78, + name: "Test Project 78", + agreementIds: [ + 699 + ] + }, + { + id: 19, + name: "Test Project 19", + agreementIds: [ + 684 + ] + }, + { + id: 311, + name: "Test Project 311", + agreementIds: [ + 799 + ] + }, + { + id: 344, + name: "Test Project 344", + agreementIds: [ + 801 + ] + }, + { + id: 344, + name: "Test Project 344", + agreementIds: [ + 800 + ] + }, + { + id: 344, + name: "Test Project 344", + agreementIds: [ + 802 + ] + }, + { + id: 344, + name: "Test Project 344", + agreementIds: [ + 803 + ] + }, + { + id: 344, + name: "Test Project 344", + agreementIds: [ + 804 + ] + }, + { + id: 344, + name: "Test Project 344", + agreementIds: [ + 805 + ] + }, + { + id: 149, + name: "Test Project 149", + agreementIds: [ + 807 + ] + }, + { + id: 149, + name: "Test Project 149", + agreementIds: [ + 806 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 809 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 810 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 812 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 693 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 811 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 813 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 814 + ] + }, + { + id: 19, + name: "Test Project 19", + agreementIds: [ + 681 + ] + }, + { + id: 180, + name: "Test Project 180", + agreementIds: [ + 815 + ] + } + ], +}); diff --git a/client/src/js/mock/api/AitReport/getRentalAgreementsLite.js b/client/src/js/mock/api/AitReport/getRentalAgreementsLite.js new file mode 100644 index 000000000..014b354b1 --- /dev/null +++ b/client/src/js/mock/api/AitReport/getRentalAgreementsLite.js @@ -0,0 +1,216 @@ +import Moment from "moment"; + +export const getRentalAgreementsLite = (dateTime) => { + return { + data: [ + { + id: 609, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(1, "days").format() + }, + { + id: 621, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(2, "days").format() + }, + { + id: 622, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(3, "days").format() + }, + { + id: 607, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(4, "days").format() + }, + { + id: 606, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(5, "days").format() + }, + { + id: 611, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(6, "days").format() + }, + { + id: 673, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(7, "days").format() + }, + { + id: 612, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(8, "days").format() + }, + { + id: 614, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(9, "days").format() + }, + { + id: 615, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(10, "days").format() + }, + { + id: 623, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(11, "days").format() + }, + { + id: 616, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(12, "days").format() + }, + { + id: 627, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(13, "days").format() + }, + { + id: 624, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(14, "days").format() + }, + { + id: 608, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(15, "days").format() + }, + { + id: 683, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(16, "days").format() + }, + { + id: 637, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(17, "days").format() + }, + { + id: 674, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(18, "days").format() + }, + { + id: 636, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(19, "days").format() + }, + { + id: 689, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(20, "days").format() + }, + { + id: 685, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(21, "days").format() + }, + { + id: 686, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(22, "days").format() + }, + { + id: 691, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(23, "days").format() + }, + { + id: 687, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(24, "days").format() + }, + { + id: 690, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(25, "days").format() + }, + { + id: 688, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(26, "days").format() + }, + { + id: 692, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(27, "days").format() + }, + { + id: 695, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(28, "days").format() + }, + { + id: 694, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(1, "months").format() + }, + { + id: 696, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(1, "months").add(1, "days").format() + }, + { + id: 697, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(1, "months").add(2, "days").format() + }, + { + id: 698, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(1, "months").add(3, "days").format() + }, + { + id: 699, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(1, "months").add(4, "days").format() + }, + { + id: 684, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(1, "months").add(5, "days").format() + }, + { + id: 799, + datedOn: Moment.utc(dateTime).add(1, "days").format() + }, + { + id: 801, + datedOn: Moment.utc(dateTime).add(2, "days").format() + }, + { + id: 800, + datedOn: Moment.utc(dateTime).add(3, "days").format() + }, + { + id: 802, + datedOn: Moment.utc(dateTime).add(4, "days").format() + }, + { + id: 803, + datedOn: Moment.utc(dateTime).add(5, "days").format() + }, + { + id: 804, + datedOn: Moment.utc(dateTime).add(6, "days").format() + }, + { + id: 805, + datedOn: Moment.utc(dateTime).add(7, "days").format() + }, + { + id: 807, + datedOn: Moment.utc(dateTime).add(8, "days").format() + }, + { + id: 806, + datedOn: Moment.utc(dateTime).add(9, "days").format() + }, + { + id: 809, + datedOn: Moment.utc(dateTime).add(10, "days").format() + }, + { + id: 810, + datedOn: Moment.utc(dateTime).add(11, "days").format() + }, + { + id: 812, + datedOn: Moment.utc(dateTime).add(12, "days").format() + }, + { + id: 693, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(1, "months").add(6, "days").format() + }, + { + id: 811, + datedOn: Moment.utc(dateTime).add(13, "days").format() + }, + { + id: 813, + datedOn: Moment.utc(dateTime).add(14, "days").format() + }, + { + id: 814, + datedOn: Moment.utc(dateTime).add(15, "days").format() + }, + { + id: 681, + datedOn: Moment.utc(dateTime).subtract(1, "year").add(1, "months").add(7, "days").format() + }, + { + id: 815, + datedOn: Moment.utc(dateTime).add(16, "days").format() + } + ], + }; +}; diff --git a/client/src/js/mock/api/AitReport/searchAitReport.js b/client/src/js/mock/api/AitReport/searchAitReport.js new file mode 100644 index 000000000..a095417d1 --- /dev/null +++ b/client/src/js/mock/api/AitReport/searchAitReport.js @@ -0,0 +1,684 @@ +import moment from "moment"; + +export const searchAitReport = (dateTime) => { + return { + data: [ + { + id: 681, + rentalAgreementNumber: "19-8-0177", + equipmentId: 13623, + equipmentCode: "EC13623", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 19, + projectNumber: "8953", + projectName: "Test Project 19", + datedOn: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(7, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(7, "days").hour(0).minute(0).second(0).format() + }, + { + id: 684, + rentalAgreementNumber: "19-8-0179", + equipmentId: 6030, + equipmentCode: "EC6030", + districtEquipmentTypeId: 1225, + districtEquipmentName: "Eq Type 1225", + projectId: 19, + projectNumber: "8953", + projectName: "Test Project 19", + datedOn: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(5, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(5, "days").hour(0).minute(0).second(0).format() + }, + { + id: 636, + rentalAgreementNumber: "19-8-0173", + equipmentId: 5666, + equipmentCode: "EC5666", + districtEquipmentTypeId: 1225, + districtEquipmentName: "Eq Type 1225", + projectId: 19, + projectNumber: "8953", + projectName: "Test Project 19", + datedOn: moment.utc(dateTime).subtract(1, "years").add(19, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(19, "days").hour(0).minute(0).second(0).format() + }, + { + id: 637, + rentalAgreementNumber: "19-8-0174", + equipmentId: 9642, + equipmentCode: "EC9642", + districtEquipmentTypeId: 1225, + districtEquipmentName: "Eq Type 1225", + projectId: 19, + projectNumber: "8953", + projectName: "Test Project 19", + datedOn: moment.utc(dateTime).subtract(1, "years").add(17, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(17, "days").hour(0).minute(0).second(0).format() + }, + { + id: 608, + rentalAgreementNumber: "19-8-0161", + equipmentId: 13623, + equipmentCode: "EC13623", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 19, + projectNumber: "8953", + projectName: "Test Project 19", + datedOn: moment.utc(dateTime).subtract(1, "years").add(15, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(15, "days").hour(0).minute(0).second(0).format() + }, + { + id: 606, + rentalAgreementNumber: "19-8-0159", + equipmentId: 6000, + equipmentCode: "EC6000", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 19, + projectNumber: "8953", + projectName: "Test Project 19", + datedOn: moment.utc(dateTime).subtract(1, "years").add(5, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(5, "days").hour(0).minute(0).second(0).format() + }, + { + id: 607, + rentalAgreementNumber: "19-8-0160", + equipmentId: 5845, + equipmentCode: "EC5845", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 19, + projectNumber: "8953", + projectName: "Test Project 19", + datedOn: moment.utc(dateTime).subtract(1, "years").add(4, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(4, "days").hour(0).minute(0).second(0).format() + }, + { + id: 622, + rentalAgreementNumber: "19-8-0169", + equipmentId: 15216, + equipmentCode: "EC15216", + districtEquipmentTypeId: 1209, + districtEquipmentName: "Eq Type 1209", + projectId: 35, + projectNumber: "5633", + projectName: "Test Project 35", + datedOn: moment.utc(dateTime).subtract(1, "years").add(3, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(3, "days").hour(0).minute(0).second(0).format() + }, + { + id: 621, + rentalAgreementNumber: "19-8-0168", + equipmentId: 15205, + equipmentCode: "EC15205", + districtEquipmentTypeId: 1209, + districtEquipmentName: "Eq Type 1209", + projectId: 35, + projectNumber: "5633", + projectName: "Test Project 35", + datedOn: moment.utc(dateTime).subtract(1, "years").add(2, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(2, "days").hour(0).minute(0).second(0).format() + }, + { + id: 697, + rentalAgreementNumber: "19-8-0192", + equipmentId: 6238, + equipmentCode: "EC6238", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 62, + projectNumber: "5196", + projectName: "Test Project 62", + datedOn: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(2, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(2, "days").hour(0).minute(0).second(0).format() + }, + { + id: 695, + rentalAgreementNumber: "19-8-0190", + equipmentId: 6619, + equipmentCode: "EC6619", + districtEquipmentTypeId: 1212, + districtEquipmentName: "Eq Type 1212", + projectId: 73, + projectNumber: "1918", + projectName: "Test Project 73", + datedOn: moment.utc(dateTime).subtract(1, "years").add(28, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(28, "days").hour(0).minute(0).second(0).format() + }, + { + id: 699, + rentalAgreementNumber: "19-8-0194", + equipmentId: 15478, + equipmentCode: "EC15478", + districtEquipmentTypeId: 1198, + districtEquipmentName: "Eq Type 1198", + projectId: 78, + projectNumber: "8578", + projectName: "Test Project 78", + datedOn: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(4, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(4, "days").hour(0).minute(0).second(0).format() + }, + { + id: 698, + rentalAgreementNumber: "19-8-0193", + equipmentId: 22541, + equipmentCode: "EC22541", + districtEquipmentTypeId: 1228, + districtEquipmentName: "Eq Type 1228", + projectId: 78, + projectNumber: "8578", + projectName: "Test Project 78", + datedOn: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(3, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(3, "days").hour(0).minute(0).second(0).format() + }, + { + id: 694, + rentalAgreementNumber: "19-8-0189", + equipmentId: 18723, + equipmentCode: "EC18723", + districtEquipmentTypeId: 1228, + districtEquipmentName: "Eq Type 1228", + projectId: 78, + projectNumber: "8578", + projectName: "Test Project 78", + datedOn: moment.utc(dateTime).subtract(1, "years").add(1, "months").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(1, "months").hour(0).minute(0).second(0).format() + }, + { + id: 612, + rentalAgreementNumber: "19-8-0164", + equipmentId: 15564, + equipmentCode: "TAZC403", + districtEquipmentTypeId: 1198, + districtEquipmentName: "Eq Type 1198", + projectId: 78, + projectNumber: "8578", + projectName: "Test Project 78", + datedOn: moment.utc(dateTime).subtract(1, "years").add(8, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(8, "days").hour(0).minute(0).second(0).format() + }, + { + id: 616, + rentalAgreementNumber: "19-8-0167", + equipmentId: 15474, + equipmentCode: "MARC407", + districtEquipmentTypeId: 1186, + districtEquipmentName: "Eq Type 1186", + projectId: 182, + projectNumber: "182", + projectName: "Test Project 182", + datedOn: moment.utc(dateTime).subtract(1, "years").add(12, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(12, "days").hour(0).minute(0).second(0).format() + }, + { + id: 615, + rentalAgreementNumber: "19-8-0166", + equipmentId: 5786, + equipmentCode: "HAUB07", + districtEquipmentTypeId: 1186, + districtEquipmentName: "Eq Type 1186", + projectId: 182, + projectNumber: "182", + projectName: "Test Project 182", + datedOn: moment.utc(dateTime).subtract(1, "years").add(10, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(10, "days").hour(0).minute(0).second(0).format() + }, + { + id: 686, + rentalAgreementNumber: "19-8-0181", + equipmentId: 6164, + equipmentCode: "EC6164", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 179, + projectNumber: "TEST-179", + projectName: "Test Project 179", + datedOn: moment.utc(dateTime).subtract(1, "years").add(22, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(22, "days").hour(0).minute(0).second(0).format() + }, + { + id: 685, + rentalAgreementNumber: "19-8-0180", + equipmentId: 6432, + equipmentCode: "EC6432", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 179, + projectNumber: "TEST-179", + projectName: "Test Project 179", + datedOn: moment.utc(dateTime).subtract(1, "years").add(21, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(21, "days").hour(0).minute(0).second(0).format() + }, + { + id: 674, + rentalAgreementNumber: "19-8-0176", + equipmentId: 5746, + equipmentCode: "EC5746", + districtEquipmentTypeId: 1225, + districtEquipmentName: "Eq Type 1225", + projectId: 179, + projectNumber: "TEST-179", + projectName: "Test Project 179", + datedOn: moment.utc(dateTime).subtract(1, "years").add(18, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(18, "days").hour(0).minute(0).second(0).format() + }, + { + id: 624, + rentalAgreementNumber: "19-8-0171", + equipmentId: 25525, + equipmentCode: "EC25525", + districtEquipmentTypeId: 1185, + districtEquipmentName: "Eq Type 1185", + projectId: 179, + projectNumber: "TEST-179", + projectName: "Test Project 179", + datedOn: moment.utc(dateTime).subtract(1, "years").add(14, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(14, "days").hour(0).minute(0).second(0).format() + }, + { + id: 627, + rentalAgreementNumber: "19-8-0172", + equipmentId: 5909, + equipmentCode: "CHRE18", + districtEquipmentTypeId: 1225, + districtEquipmentName: "Eq Type 1225", + projectId: 179, + projectNumber: "TEST-179", + projectName: "Test Project 179", + datedOn: moment.utc(dateTime).subtract(1, "years").add(13, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(13, "days").hour(0).minute(0).second(0).format() + }, + { + id: 623, + rentalAgreementNumber: "19-8-0170", + equipmentId: 25524, + equipmentCode: "NTST001", + districtEquipmentTypeId: 1185, + districtEquipmentName: "Eq Type 1185", + projectId: 179, + projectNumber: "TEST-179", + projectName: "Test Project 179", + datedOn: moment.utc(dateTime).subtract(1, "years").add(11, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(11, "days").hour(0).minute(0).second(0).format() + }, + { + id: 673, + rentalAgreementNumber: "19-8-0175", + equipmentId: 25525, + equipmentCode: "EC25525", + districtEquipmentTypeId: 1185, + districtEquipmentName: "Eq Type 1185", + projectId: 179, + projectNumber: "TEST-179", + projectName: "Test Project 179", + datedOn: moment.utc(dateTime).subtract(1, "years").add(7, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(7, "days").hour(0).minute(0).second(0).format() + }, + { + id: 806, + rentalAgreementNumber: "20-8-0028", + equipmentId: 25609, + equipmentCode: "EC25609", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 149, + projectNumber: "78", + projectName: "Test Project 149", + datedOn: moment.utc(dateTime).add(9, "days").format(), + startDate: moment.utc(dateTime).add(9, "days").hour(0).minute(0).second(0).format() + }, + { + id: 807, + rentalAgreementNumber: "20-8-0029", + equipmentId: 25610, + equipmentCode: "EC25610", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 149, + projectNumber: "78", + projectName: "Test Project 149", + datedOn: moment.utc(dateTime).add(8, "days").format(), + startDate: moment.utc(dateTime).add(8, "days").hour(0).minute(0).second(0).format() + }, + { + id: 815, + rentalAgreementNumber: "22-8-0016", + equipmentId: 25609, + equipmentCode: "EC25609", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).add(16, "days").format(), + startDate: moment.utc(dateTime).add(16, "days").hour(0).minute(0).second(0).format() + }, + { + id: 814, + rentalAgreementNumber: "22-8-0015", + equipmentId: 25609, + equipmentCode: "EC25609", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).add(15, "days").format(), + startDate: moment.utc(dateTime).add(15, "days").hour(0).minute(0).second(0).format() + }, + { + id: 813, + rentalAgreementNumber: "22-8-0014", + equipmentId: 25610, + equipmentCode: "EC25610", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).add(14, "days").format(), + startDate: moment.utc(dateTime).add(14, "days").hour(0).minute(0).second(0).format() + }, + { + id: 811, + rentalAgreementNumber: "22-8-0012", + equipmentId: 25610, + equipmentCode: "EC25610", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).add(13, "days").format(), + startDate: moment.utc(dateTime).add(13, "days").hour(0).minute(0).second(0).format() + }, + { + id: 693, + rentalAgreementNumber: "19-8-0188", + equipmentId: 10276, + equipmentCode: "EC10276", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(6, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(6, "days").hour(0).minute(0).second(0).format() + }, + { + id: 812, + rentalAgreementNumber: "22-8-0013", + equipmentId: 25608, + equipmentCode: "EC25608", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).add(12, "days").format(), + startDate: moment.utc(dateTime).add(12, "days").hour(0).minute(0).second(0).format() + }, + { + id: 810, + rentalAgreementNumber: "20-8-0031", + equipmentId: 25610, + equipmentCode: "EC25610", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).add(11, "days").format(), + startDate: moment.utc(dateTime).add(11, "days").hour(0).minute(0).second(0).format() + }, + { + id: 809, + rentalAgreementNumber: "20-8-0030", + equipmentId: 25609, + equipmentCode: "EC25609", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).add(10, "days").format(), + startDate: moment.utc(dateTime).add(10, "days").hour(0).minute(0).second(0).format() + }, + { + id: 692, + rentalAgreementNumber: "19-8-0187", + equipmentId: 9826, + equipmentCode: "EC9826", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).subtract(1, "years").add(27, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(27, "days").hour(0).minute(0).second(0).format() + }, + { + id: 688, + rentalAgreementNumber: "19-8-0183", + equipmentId: 6158, + equipmentCode: "EC6158", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).subtract(1, "years").add(26, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(26, "days").hour(0).minute(0).second(0).format() + }, + { + id: 690, + rentalAgreementNumber: "19-8-0185", + equipmentId: 6155, + equipmentCode: "EC6155", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).subtract(1, "years").add(25, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(25, "days").hour(0).minute(0).second(0).format() + }, + { + id: 687, + rentalAgreementNumber: "19-8-0182", + equipmentId: 6162, + equipmentCode: "EC6162", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).subtract(1, "years").add(24, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(24, "days").hour(0).minute(0).second(0).format() + }, + { + id: 691, + rentalAgreementNumber: "19-8-0186", + equipmentId: 10615, + equipmentCode: "EC10615", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).subtract(1, "years").add(23, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(23, "days").hour(0).minute(0).second(0).format() + }, + { + id: 689, + rentalAgreementNumber: "19-8-0184", + equipmentId: 6157, + equipmentCode: "EC6157", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).subtract(1, "years").add(20, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(20, "days").hour(0).minute(0).second(0).format() + }, + { + id: 683, + rentalAgreementNumber: "19-8-0178", + equipmentId: 7041, + equipmentCode: "EC7041", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).subtract(1, "years").add(16, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(16, "days").hour(0).minute(0).second(0).format() + }, + { + id: 614, + rentalAgreementNumber: "19-8-0165", + equipmentId: 18606, + equipmentCode: "TDF401", + districtEquipmentTypeId: 1198, + districtEquipmentName: "Eq Type 1198", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).subtract(1, "years").add(9, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(9, "days").hour(0).minute(0).second(0).format() + }, + { + id: 611, + rentalAgreementNumber: "19-8-0163", + equipmentId: 5988, + equipmentCode: "EC5988", + districtEquipmentTypeId: 1210, + districtEquipmentName: "Eq Type 1210", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).subtract(1, "years").add(6, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(6, "days").hour(0).minute(0).second(0).format() + }, + { + id: 609, + rentalAgreementNumber: "2019-126-0023", + equipmentId: 15156, + equipmentCode: "EC15156", + districtEquipmentTypeId: 1209, + districtEquipmentName: "Eq Type 1209", + projectId: 180, + projectNumber: "Testproj-180", + projectName: "Test Project 180", + datedOn: moment.utc(dateTime).subtract(1, "years").add(1, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(1, "days").hour(0).minute(0).second(0).format() + }, + { + id: 799, + rentalAgreementNumber: "20-8-0021", + equipmentId: 12388, + equipmentCode: "EC12388", + districtEquipmentTypeId: 1227, + districtEquipmentName: "Eq Type 1227", + projectId: 311, + projectNumber: "123456", + projectName: "Test Project 311", + datedOn: moment.utc(dateTime).add(1, "days").format(), + startDate: moment.utc(dateTime).add(1, "days").hour(0).minute(0).second(0).format() + }, + { + id: 696, + rentalAgreementNumber: "19-8-0191", + equipmentId: 6618, + equipmentCode: "EC6618", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 311, + projectNumber: "123456", + projectName: "Test Project 311", + datedOn: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(1, "days").format(), + startDate: moment.utc(dateTime).subtract(1, "years").add(1, "months").add(1, "days").hour(0).minute(0).second(0).format() + }, + { + id: 805, + rentalAgreementNumber: "20-8-0027", + equipmentId: 25608, + equipmentCode: "EC25608", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 344, + projectNumber: "123456789", + projectName: "Test Project 344", + datedOn: moment.utc(dateTime).add(7, "days").format(), + startDate: moment.utc(dateTime).add(7, "days").hour(0).minute(0).second(0).format() + }, + { + id: 804, + rentalAgreementNumber: "20-8-0026", + equipmentId: 25614, + equipmentCode: "EC25614", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 344, + projectNumber: "123456789", + projectName: "Test Project 344", + datedOn: moment.utc(dateTime).add(6, "days").format(), + startDate: moment.utc(dateTime).add(6, "days").hour(0).minute(0).second(0).format() + }, + { + id: 803, + rentalAgreementNumber: "20-8-0025", + equipmentId: 25613, + equipmentCode: "EC25613", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 344, + projectNumber: "123456789", + projectName: "Test Project 344", + datedOn: moment.utc(dateTime).add(5, "days").format(), + startDate: moment.utc(dateTime).add(5, "days").hour(0).minute(0).second(0).format() + }, + { + id: 802, + rentalAgreementNumber: "20-8-0024", + equipmentId: 25609, + equipmentCode: "EC25609", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 344, + projectNumber: "123456789", + projectName: "Test Project 344", + datedOn: moment.utc(dateTime).add(4, "days").format(), + startDate: moment.utc(dateTime).add(4, "days").hour(0).minute(0).second(0).format() + }, + { + id: 800, + rentalAgreementNumber: "20-8-0022", + equipmentId: 25608, + equipmentCode: "EC25608", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 344, + projectNumber: "123456789", + projectName: "Test Project 344", + datedOn: moment.utc(dateTime).add(3, "days").format(), + startDate: moment.utc(dateTime).add(3, "days").hour(0).minute(0).second(0).format() + }, + { + id: 801, + rentalAgreementNumber: "20-8-0023", + equipmentId: 25609, + equipmentCode: "EC25609", + districtEquipmentTypeId: 1214, + districtEquipmentName: "Eq Type 1214", + projectId: 344, + projectNumber: "123456789", + projectName: "Test Project 344", + datedOn: moment.utc(dateTime).add(2, "days").format(), + startDate: moment.utc(dateTime).add(2, "days").hour(0).minute(0).second(0).format() + } + ], + } +}; diff --git a/client/src/js/mock/api/getCounts.js b/client/src/js/mock/api/getCounts.js new file mode 100644 index 000000000..b0024e2a8 --- /dev/null +++ b/client/src/js/mock/api/getCounts.js @@ -0,0 +1,8 @@ +export const getCounts = () => ({ + data: { + unapprovedOwners: 0, + unapprovedEquipment: 4, + hiredEquipment: 0, + inProgressRentalRequests: 4, + }, +}); \ No newline at end of file diff --git a/client/src/js/mock/api/getCurrentUser.js b/client/src/js/mock/api/getCurrentUser.js new file mode 100644 index 000000000..343d12e8c --- /dev/null +++ b/client/src/js/mock/api/getCurrentUser.js @@ -0,0 +1,167 @@ +export const getCurrentUser = () => ({ + data: { + id: 123, + smUserId: "MNAME", + surname: "Name", + givenName: "My", + displayName: "My Name", + userGuid: "123456AB789012C3456D78901EF2A3BC", + agreementCity: null, + smAuthorizationDirectory: null, + businessId: null, + businessGuid: null, + environment: "Development", + businessUser: false, + district: { + id: 1, + districtNumber: 1, + name: "District 1", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 1, + regionId: 1, + concurrencyControlNumber: 1, + region: null + }, + userDistricts: [], + userRoles: [ + { + id: 1231, + effectiveDate: "2023-01-01T12:00:00Z", + expiryDate: "2099-01-01T12:00:00Z", + userId: 123, + roleId: 1, + concurrencyControlNumber: 1, + role: { + id: 1, + name: "System Administrator", + description: "Full Access to the Whole System", + concurrencyControlNumber: 1, + rolePermissions: [ + { + id: 27, + permissionId: 11, + roleId: 1, + concurrencyControlNumber: 0, + permission: { + id: 11, + code: "WriteAccess", + name: "Write Access", + description: "Permission to add, update, delete records", + concurrencyControlNumber: 0 + } + }, + { + id: 1, + permissionId: 1, + roleId: 1, + concurrencyControlNumber: 0, + permission: { + id: 1, + code: "Login", + name: "Login", + description: "Permission to login to the application and perform all Clerk functions within their designated District", + concurrencyControlNumber: 0 + } + }, + { + id: 2, + permissionId: 7, + roleId: 1, + concurrencyControlNumber: 0, + permission: { + id: 7, + code: "DistrictCodeTableManagement", + name: "District Code Table Management", + description: "Gives the user access to the District Code Table Management screens", + concurrencyControlNumber: 0 + } + }, + { + id: 3, + permissionId: 6, + roleId: 1, + concurrencyControlNumber: 0, + permission: { + id: 6, + code: "CodeTableManagement", + name: "Code Table Management", + description: "Gives the user access to the Code Table Management screens", + concurrencyControlNumber: 0 + } + }, + { + id: 4, + permissionId: 2, + roleId: 1, + concurrencyControlNumber: 0, + permission: { + id: 2, + code: "UserManagement", + name: "User Management", + description: "Gives the user access to the User Management screens", + concurrencyControlNumber: 0 + } + }, + { + id: 5, + permissionId: 3, + roleId: 1, + concurrencyControlNumber: 0, + permission: { + id: 3, + code: "RolesAndPermissions", + name: "Roles and Permissions", + description: "Gives the user access to the Roles and Permissions screens", + concurrencyControlNumber: 0 + } + }, + { + id: 6, + permissionId: 4, + roleId: 1, + concurrencyControlNumber: 0, + permission: { + id: 4, + code: "Admin", + name: "Administration", + description: "Allows the user to perform special administrative tasks", + concurrencyControlNumber: 0 + } + }, + { + id: 8, + permissionId: 9, + roleId: 1, + concurrencyControlNumber: 0, + permission: { + id: 9, + code: "DistrictRollover", + name: "District Rollover", + description: "Permission to kickoff the annual district rollover process", + concurrencyControlNumber: 0 + } + }, + { + id: 9, + permissionId: 10, + roleId: 1, + concurrencyControlNumber: 0, + permission: { + id: 10, + code: "Version", + name: "Version", + description: "Permission to view application's version page", + concurrencyControlNumber: 0 + } + } + ] + } + } + ], + }, +}); + +export const getCurrentUserFavourites = () => ({ + data: [], +}); diff --git a/client/src/js/mock/api/getDistricts.js b/client/src/js/mock/api/getDistricts.js new file mode 100644 index 000000000..fe5a25823 --- /dev/null +++ b/client/src/js/mock/api/getDistricts.js @@ -0,0 +1,251 @@ +export const getDistricts = () => ({ + data: [ + { + id: 1, + districtNumber: 1, + name: "District 1", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 1, + regionId: 1, + concurrencyControlNumber: 1, + region: { + id: 1, + name: "Region 1", + regionNumber: 1, + ministryRegionId: 1, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 2, + districtNumber: 2, + name: "District 2", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 2, + regionId: 1, + concurrencyControlNumber: 1, + region: { + id: 1, + name: "Region 1", + regionNumber: 1, + ministryRegionId: 1, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 3, + districtNumber: 3, + name: "District 3", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 3, + regionId: 2, + concurrencyControlNumber: 1, + region: { + id: 2, + name: "Region 2", + regionNumber: 2, + ministryRegionId: 2, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 4, + districtNumber: 4, + name: "District 4", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 4, + regionId: 3, + concurrencyControlNumber: 1, + region: { + id: 3, + name: "Region 3", + regionNumber: 3, + ministryRegionId: 3, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 5, + districtNumber: 5, + name: "District 5", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 5, + regionId: 3, + concurrencyControlNumber: 1, + region: { + id: 3, + name: "Region 3", + regionNumber: 3, + ministryRegionId: 3, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 6, + districtNumber: 6, + name: "District 6", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 6, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 7, + districtNumber: 7, + name: "District 7", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 7, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 8, + districtNumber: 8, + name: "District 8", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 8, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 9, + districtNumber: 9, + name: "District 9", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 9, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 10, + districtNumber: 10, + name: "District 10", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 10, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 11, + districtNumber: 11, + name: "District 11", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 11, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 12, + districtNumber: 12, + name: "District 12", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 12, + regionId: 5, + concurrencyControlNumber: 1, + region: { + id: 5, + name: "Region 5", + regionNumber: 5, + ministryRegionId: 5, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + }, + { + id: 13, + districtNumber: 13, + name: "District 13", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 13, + regionId: 5, + concurrencyControlNumber: 1, + region: { + id: 5, + name: "Region 5", + regionNumber: 5, + ministryRegionId: 5, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + ], +}); diff --git a/client/src/js/mock/api/getFavourites.js b/client/src/js/mock/api/getFavourites.js new file mode 100644 index 000000000..baca25154 --- /dev/null +++ b/client/src/js/mock/api/getFavourites.js @@ -0,0 +1,45 @@ +export const getFavourites = () => { + return { + customFav: { + 1: { + id: 1, + type: "customFav", + name: "Custom Fav 1", + value: JSON.stringify({ + date: "1900-01-01", + items: [1], + }), + isDefault: false, + userId: 123, + districtId: 1, + concurrencyVersionNumber: 1, + }, + 2: { + id: 2, + type: "customFav", + name: "Custom Fav 2", + value: JSON.stringify({ + date: "1900-01-02", + items: [1, 2], + }), + isDefault: false, + userId: 123, + districtId: 1, + concurrencyVersionNumber: 1, + }, + 3: { + id: 3, + type: "customFav", + name: "Custom Fav 3", + value: JSON.stringify({ + date: "1900-01-03", + items: [1, 2, 3], + }), + isDefault: true, + userId: 123, + districtId: 1, + concurrencyVersionNumber: 1, + }, + } + }; +}; diff --git a/client/src/js/mock/api/getFiscalYears.js b/client/src/js/mock/api/getFiscalYears.js new file mode 100644 index 000000000..2a401a4b3 --- /dev/null +++ b/client/src/js/mock/api/getFiscalYears.js @@ -0,0 +1,6 @@ +export const getFiscalYears = () => ({ + data: [ + "2021/2022", + "2022/2023" + ], +}); \ No newline at end of file diff --git a/client/src/js/mock/api/getLocalAreas.js b/client/src/js/mock/api/getLocalAreas.js new file mode 100644 index 000000000..fc678d61e --- /dev/null +++ b/client/src/js/mock/api/getLocalAreas.js @@ -0,0 +1,164 @@ +export const getLocalAreas = () => ({ + data: [ + { + id: 1, + localAreaNumber: 1, + name: "Local Area 1", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 1, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 2, + localAreaNumber: 2, + name: "Local Area 2", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 2, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 3, + localAreaNumber: 3, + name: "Local Area 3", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 3, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 4, + localAreaNumber: 4, + name: "Local Area 4", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 4, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 5, + localAreaNumber: 5, + name: "Local Area 5", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 1, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 6, + localAreaNumber: 6, + name: "Local Area 6", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 2, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 7, + localAreaNumber: 7, + name: "Local Area 7", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 3, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 8, + localAreaNumber: 8, + name: "Local Area 8", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 4, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 9, + localAreaNumber: 9, + name: "Local Area 9", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 1, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 10, + localAreaNumber: 10, + name: "Local Area 10", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 2, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 11, + localAreaNumber: 11, + name: "Local Area 11", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 3, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 12, + localAreaNumber: 12, + name: "Local Area 12", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 4, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 13, + localAreaNumber: 13, + name: "Local Area 13", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 1, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 14, + localAreaNumber: 14, + name: "Un-Assigned", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 2, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 15, + localAreaNumber: 15, + name: "Un-Assigned", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 3, + concurrencyControlNumber: 1, + serviceArea: null + }, + { + id: 16, + localAreaNumber: 16, + name: "Un-Assigned", + endDate: null, + startDate: "0001-01-01T00:00:00Z", + serviceAreaId: 4, + concurrencyControlNumber: 1, + serviceArea: null + } + ], +}); \ No newline at end of file diff --git a/client/src/js/mock/api/getPermissions.js b/client/src/js/mock/api/getPermissions.js new file mode 100644 index 000000000..6ac5cdd88 --- /dev/null +++ b/client/src/js/mock/api/getPermissions.js @@ -0,0 +1,64 @@ +export const getPermissions = () => ({ + data: [ + { + id: 1, + code: "Login", + name: "Login", + description: "Permission to login to the application and perform all Clerk functions within their designated District" + }, + { + id: 2, + code: "UserManagement", + name: "User Management", + description: "Gives the user access to the User Management screens" + }, + { + id: 3, + code: "RolesAndPermissions", + name: "Roles and Permissions", + description: "Gives the user access to the Roles and Permissions screens" + }, + { + id: 4, + code: "Admin", + name: "Administration", + description: "Allows the user to perform special administrative tasks" + }, + { + id: 6, + code: "CodeTableManagement", + name: "Code Table Management", + description: "Gives the user access to the Code Table Management screens" + }, + { + id: 7, + code: "DistrictCodeTableManagement", + name: "District Code Table Management", + description: "Gives the user access to the District Code Table Management screens" + }, + { + id: 8, + code: "BusinessLogin", + name: "Business Login", + description: "Permission to login to the business or owner facing application" + }, + { + id: 9, + code: "DistrictRollover", + name: "District Rollover", + description: "Permission to kickoff the annual district rollover process" + }, + { + id: 10, + code: "Version", + name: "Version", + description: "Permission to view application's version page" + }, + { + id: 11, + code: "WriteAccess", + name: "Write Access", + description: "Permission to add, update, delete records" + } + ], +}); \ No newline at end of file diff --git a/client/src/js/mock/api/getRegions.js b/client/src/js/mock/api/getRegions.js new file mode 100644 index 000000000..49fd4359b --- /dev/null +++ b/client/src/js/mock/api/getRegions.js @@ -0,0 +1,49 @@ +export const getRegions = () => ({ + data: [ + { + id: 1, + name: "Region 1", + regionNumber: 1, + ministryRegionId: 1, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + }, + { + id: 2, + name: "Region 2", + regionNumber: 2, + ministryRegionId: 2, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + }, + { + id: 3, + name: "Region 3", + regionNumber: 3, + ministryRegionId: 3, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + }, + { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + }, + { + id: 5, + name: "Region 5", + regionNumber: 5, + ministryRegionId: 5, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + }, + ], +}); \ No newline at end of file diff --git a/client/src/js/mock/api/getRolloverStatus.js b/client/src/js/mock/api/getRolloverStatus.js new file mode 100644 index 000000000..5ed6fff6e --- /dev/null +++ b/client/src/js/mock/api/getRolloverStatus.js @@ -0,0 +1,27 @@ +export const getRolloverStatus = () => ({ + data: { + id: 1, + currentFiscalYear: 2021, + nextFiscalYear: 2022, + rolloverStartDate: "2021-04-01T16:06:28.276178Z", + rolloverEndDate: "2021-04-01T16:09:23.595126Z", + localAreaCount: 16, + districtEquipmentTypeCount: 99, + localAreaCompleteCount: 16, + districtEquipmentTypeCompleteCount: 99, + progressPercentage: null, + displayRolloverMessage: false, + concurrencyControlNumber: 4781, + district: { + id: 1, + districtNumber: 1, + name: "District 1", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 1, + regionId: 1, + concurrencyControlNumber: 1, + region: null + } + }, +}); \ No newline at end of file diff --git a/client/src/js/mock/api/getServiceAreas.js b/client/src/js/mock/api/getServiceAreas.js new file mode 100644 index 000000000..0631925d9 --- /dev/null +++ b/client/src/js/mock/api/getServiceAreas.js @@ -0,0 +1,928 @@ +export const getServiceAreas = () => ({ + data: [ + { + id: 1, + name: "Service Area 1", + areaNumber: 401, + ministryServiceAreaId: 1, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 1|#101 - 10001 101st Ave|District 1, B.C.|V1A 1M1", + phone: "(250) 456-7890", + fax: "(250) 456-7891", + supportingDocuments: "Document 1|Document 2", + districtId: 1, + concurrencyControlNumber: 1, + district: { + id: 1, + districtNumber: 1, + name: "District 1", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 1, + regionId: 1, + concurrencyControlNumber: 1, + region: { + id: 1, + name: "Region 1", + regionNumber: 1, + ministryRegionId: 1, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 2, + name: "Service Area 2", + areaNumber: 402, + ministryServiceAreaId: 2, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 1|#102 - 10001 101st Ave|District 1, B.C.|V1A 1M2", + phone: "(250) 456-7892", + fax: "(250) 456-7893", + supportingDocuments: "Document 1|Document 2", + districtId: 1, + concurrencyControlNumber: 1, + district: { + id: 1, + districtNumber: 1, + name: "District 1", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 1, + regionId: 1, + concurrencyControlNumber: 1, + region: { + id: 1, + name: "Region 1", + regionNumber: 1, + ministryRegionId: 1, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 3, + name: "Service Area 3", + areaNumber: 403, + ministryServiceAreaId: 3, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 1|#103 - 10001 101st Ave|District 1, B.C.|V1A 1M3", + phone: "(250) 456-7894", + fax: "(250) 456-7895", + supportingDocuments: "Document 1|Document 2", + districtId: 1, + concurrencyControlNumber: 1, + district: { + id: 1, + districtNumber: 1, + name: "District 1", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 1, + regionId: 1, + concurrencyControlNumber: 1, + region: { + id: 1, + name: "Region 1", + regionNumber: 1, + ministryRegionId: 1, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 4, + name: "Service Area 4", + areaNumber: 404, + ministryServiceAreaId: 4, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 1|#104 - 10001 101st Ave|District 1, B.C.|V1A 1M4", + phone: "(250) 456-7896", + fax: "(250) 456-7897", + supportingDocuments: "Document 1|Document 2", + districtId: 1, + concurrencyControlNumber: 1, + district: { + id: 1, + districtNumber: 1, + name: "District 1", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 1, + regionId: 1, + concurrencyControlNumber: 1, + region: { + id: 1, + name: "Region 1", + regionNumber: 1, + ministryRegionId: 1, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 5, + name: "Service Area 5", + areaNumber: 405, + ministryServiceAreaId: 5, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 2|#205 - 20001 201st Ave|District 2, B.C.|V2A 1N5", + phone: "(250) 456-7898", + fax: "(250) 456-7899", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4", + districtId: 2, + concurrencyControlNumber: 1, + district: { + id: 2, + districtNumber: 2, + name: "District 2", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 2, + regionId: 1, + concurrencyControlNumber: 1, + region: { + id: 1, + name: "Region 1", + regionNumber: 1, + ministryRegionId: 1, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 6, + name: "Service Area 6", + areaNumber: 406, + ministryServiceAreaId: 6, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 2|#206 - 20001 201st Ave|District 2, B.C.|V2A 1N6", + phone: "(250) 456-7900", + fax: "(250) 456-7901", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4", + districtId: 2, + concurrencyControlNumber: 1, + district: { + id: 2, + districtNumber: 2, + name: "District 2", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 2, + regionId: 1, + concurrencyControlNumber: 1, + region: { + id: 1, + name: "Region 1", + regionNumber: 1, + ministryRegionId: 1, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 7, + name: "Service Area 7", + areaNumber: 407, + ministryServiceAreaId: 7, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 2|#207 - 20001 201st Ave|District 2, B.C.|V2A 1N7", + phone: "(250) 456-7902", + fax: "(250) 456-7903", + supportingDocuments: "Document 1|Document 2", + districtId: 2, + concurrencyControlNumber: 1, + district: { + id: 2, + districtNumber: 2, + name: "District 2", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 2, + regionId: 1, + concurrencyControlNumber: 1, + region: { + id: 1, + name: "Region 1", + regionNumber: 1, + ministryRegionId: 1, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 8, + name: "Service Area 8", + areaNumber: 408, + ministryServiceAreaId: 8, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 3|#308 - 30001 301st Ave|District 3, B.C.|V3A 1O8", + phone: "(250) 456-7904", + fax: "(250) 456-7905", + supportingDocuments: "Document 1|Document 2", + districtId: 3, + concurrencyControlNumber: 1, + district: { + id: 3, + districtNumber: 3, + name: "District 3", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 3, + regionId: 2, + concurrencyControlNumber: 1, + region: { + id: 2, + name: "Region 2", + regionNumber: 2, + ministryRegionId: 2, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 9, + name: "Service Area 9", + areaNumber: 409, + ministryServiceAreaId: 9, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 3|#309 - 30001 301st Ave|District 3, B.C.|V3A 1O9", + phone: "(250) 456-7906", + fax: "(250) 456-7907", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4", + districtId: 3, + concurrencyControlNumber: 1, + district: { + id: 3, + districtNumber: 3, + name: "District 3", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 3, + regionId: 2, + concurrencyControlNumber: 1, + region: { + id: 2, + name: "Region 2", + regionNumber: 2, + ministryRegionId: 2, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 10, + name: "Service Area 10", + areaNumber: 410, + ministryServiceAreaId: 10, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 4|#410 - 40001 401st Ave|District 4, B.C.|V4A 2P0", + phone: "(250) 456-7908", + fax: "(250) 456-7909", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4|Document 5", + districtId: 4, + concurrencyControlNumber: 1, + district: { + id: 4, + districtNumber: 4, + name: "District 4", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 4, + regionId: 3, + concurrencyControlNumber: 1, + region: { + id: 3, + name: "Region 3", + regionNumber: 3, + ministryRegionId: 3, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 11, + name: "Service Area 11", + areaNumber: 411, + ministryServiceAreaId: 11, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 4|#411 - 40001 401st Ave|District 4, B.C.|V4A 2P1", + phone: "(250) 456-7910", + fax: "(250) 456-7911", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4", + districtId: 4, + concurrencyControlNumber: 1, + district: { + id: 4, + districtNumber: 4, + name: "District 4", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 4, + regionId: 3, + concurrencyControlNumber: 1, + region: { + id: 3, + name: "Region 3", + regionNumber: 3, + ministryRegionId: 3, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 12, + name: "Service Area 12", + areaNumber: 412, + ministryServiceAreaId: 12, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 5|#512 - 50001 501st Ave|District 5, B.C.|V5A 2Q2", + phone: "(250) 456-7912", + fax: "(250) 456-7913", + supportingDocuments: "Document 1|Document 2", + districtId: 5, + concurrencyControlNumber: 1, + district: { + id: 5, + districtNumber: 5, + name: "District 5", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 5, + regionId: 3, + concurrencyControlNumber: 1, + region: { + id: 3, + name: "Region 3", + regionNumber: 3, + ministryRegionId: 3, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 13, + name: "Service Area 13", + areaNumber: 413, + ministryServiceAreaId: 13, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 5|#513 - 50001 501st Ave|District 5, B.C.|V5A 2Q3", + phone: "(250) 456-7914", + fax: "(250) 456-7915", + supportingDocuments: "Document 1|Document 2", + districtId: 5, + concurrencyControlNumber: 1, + district: { + id: 5, + districtNumber: 5, + name: "District 5", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 5, + regionId: 3, + concurrencyControlNumber: 1, + region: { + id: 3, + name: "Region 3", + regionNumber: 3, + ministryRegionId: 3, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 14, + name: "Service Area 14", + areaNumber: 414, + ministryServiceAreaId: 14, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 6|#614 - 60001 601st Ave|District 6, B.C.|V6A 2R4", + phone: "(604) 456-7916", + fax: "(604) 456-7917", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4", + districtId: 6, + concurrencyControlNumber: 1, + district: { + id: 6, + districtNumber: 6, + name: "District 6", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 6, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 15, + name: "Service Area 15", + areaNumber: 415, + ministryServiceAreaId: 15, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 6|#615 - 60001 601st Ave|District 6, B.C.|V6A 2R5", + phone: "(604) 456-7918", + fax: "(604) 456-7919", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4|Document 5", + districtId: 6, + concurrencyControlNumber: 1, + district: { + id: 6, + districtNumber: 6, + name: "District 6", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 6, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 16, + name: "Service Area 16", + areaNumber: 416, + ministryServiceAreaId: 16, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 7|#716 - 70001 701st Ave|District 7, B.C.|V7A 2S6", + phone: "(604) 456-7920", + fax: "(604) 456-7921", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4|Document 5", + districtId: 7, + concurrencyControlNumber: 1, + district: { + id: 7, + districtNumber: 7, + name: "District 7", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 7, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 17, + name: "Service Area 17", + areaNumber: 417, + ministryServiceAreaId: 17, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 8|#817 - 80001 801st Ave|District 8, B.C.|V8A 2T7", + phone: "(604) 456-7922", + fax: "(604) 456-7923", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4|Document 5", + districtId: 8, + concurrencyControlNumber: 1, + district: { + id: 8, + districtNumber: 8, + name: "District 8", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 8, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 18, + name: "Service Area 18", + areaNumber: 418, + ministryServiceAreaId: 18, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 9|#918 - 90001 901st Ave|District 9, B.C.|V9A 2U8", + phone: "(250) 456-7924", + fax: "(250) 456-7925", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4", + districtId: 9, + concurrencyControlNumber: 1, + district: { + id: 9, + districtNumber: 9, + name: "District 9", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 9, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 19, + name: "Service Area 19", + areaNumber: 419, + ministryServiceAreaId: 19, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 10|#1019 - 10001 101st Ave|District 10, B.C.|V0B 2V9", + phone: "(250) 456-7926", + fax: "(250) 456-7927", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4", + districtId: 10, + concurrencyControlNumber: 1, + district: { + id: 10, + districtNumber: 10, + name: "District 10", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 10, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 20, + name: "Service Area 20", + areaNumber: 420, + ministryServiceAreaId: 20, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 11|#1120 - 11001 111th Ave|District 11, B.C.|V1B 2W0", + phone: "(250) 456-7928", + fax: "(250) 456-7929", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4", + districtId: 11, + concurrencyControlNumber: 1, + district: { + id: 11, + districtNumber: 11, + name: "District 11", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 11, + regionId: 4, + concurrencyControlNumber: 1, + region: { + id: 4, + name: "Region 4", + regionNumber: 4, + ministryRegionId: 4, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 21, + name: "Service Area 21", + areaNumber: 421, + ministryServiceAreaId: 21, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 12|#1221 - 12001 121st Ave|District 12, B.C.|V2B 2X1", + phone: "(250) 456-7930", + fax: "(250) 456-7931", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4", + districtId: 12, + concurrencyControlNumber: 1, + district: { + id: 12, + districtNumber: 12, + name: "District 12", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 12, + regionId: 5, + concurrencyControlNumber: 1, + region: { + id: 5, + name: "Region 5", + regionNumber: 5, + ministryRegionId: 5, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 22, + name: "Service Area 22", + areaNumber: 422, + ministryServiceAreaId: 22, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 13|#1322 - 13001 131st Ave|District 13, B.C.|V3B 2Y2", + phone: "(250) 456-7932", + fax: "(250) 456-7933", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4|Document 5", + districtId: 13, + concurrencyControlNumber: 1, + district: { + id: 13, + districtNumber: 13, + name: "District 13", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 13, + regionId: 5, + concurrencyControlNumber: 1, + region: { + id: 5, + name: "Region 5", + regionNumber: 5, + ministryRegionId: 5, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 23, + name: "Service Area 23", + areaNumber: 423, + ministryServiceAreaId: 23, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 13|#1323 - 13001 131st Ave|District 13, B.C.|V3B 2Y3", + phone: "(250) 456-7934", + fax: "(250) 456-7935", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4", + districtId: 13, + concurrencyControlNumber: 1, + district: { + id: 13, + districtNumber: 13, + name: "District 13", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 13, + regionId: 5, + concurrencyControlNumber: 1, + region: { + id: 5, + name: "Region 5", + regionNumber: 5, + ministryRegionId: 5, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 24, + name: "Service Area 24", + areaNumber: 424, + ministryServiceAreaId: 24, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 13|#1324 - 13001 131st Ave|District 13, B.C.|V3B 2Y4", + phone: "(250) 456-7936", + fax: "(250) 456-7937", + supportingDocuments: "Document 1|Document 2|Document 3|Document 4", + districtId: 13, + concurrencyControlNumber: 1, + district: { + id: 13, + districtNumber: 13, + name: "District 13", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 13, + regionId: 5, + concurrencyControlNumber: 1, + region: { + id: 5, + name: "Region 5", + regionNumber: 5, + ministryRegionId: 5, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 25, + name: "Service Area 25", + areaNumber: 425, + ministryServiceAreaId: 25, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 13|#1325 - 13001 131st Ave|District 13, B.C.|V3B 2Y5", + phone: "(250) 456-7938", + fax: "(250) 456-7939", + supportingDocuments: "Document 1|Document 2", + districtId: 13, + concurrencyControlNumber: 1, + district: { + id: 13, + districtNumber: 13, + name: "District 13", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 13, + regionId: 5, + concurrencyControlNumber: 1, + region: { + id: 5, + name: "Region 5", + regionNumber: 5, + ministryRegionId: 5, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 26, + name: "Service Area 26", + areaNumber: 426, + ministryServiceAreaId: 26, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 13|#1326 - 13001 131st Ave|District 13, B.C.|V3B 2Y6", + phone: "(250) 456-7940", + fax: "(250) 456-7941", + supportingDocuments: "Document 1|Document 2", + districtId: 13, + concurrencyControlNumber: 1, + district: { + id: 13, + districtNumber: 13, + name: "District 13", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 13, + regionId: 5, + concurrencyControlNumber: 1, + region: { + id: 5, + name: "Region 5", + regionNumber: 5, + ministryRegionId: 5, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 27, + name: "Service Area 27", + areaNumber: 427, + ministryServiceAreaId: 27, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 13|#1327 - 13001 131st Ave|District 13, B.C.|V3B 2Y7", + phone: "(250) 456-7942", + fax: "(250) 456-7943", + supportingDocuments: "Document 1|Document 2|Document 3", + districtId: 13, + concurrencyControlNumber: 1, + district: { + id: 13, + districtNumber: 13, + name: "District 13", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 13, + regionId: 5, + concurrencyControlNumber: 1, + region: { + id: 5, + name: "Region 5", + regionNumber: 5, + ministryRegionId: 5, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + { + id: 28, + name: "Service Area 28", + areaNumber: 428, + ministryServiceAreaId: 28, + fiscalStartDate: "2018-04-01T00:00:00Z", + fiscalEndDate: "2019-03-31T00:00:00Z", + address: "Ministry of Transportation and Infrastructure|District 13|#1328 - 13001 131st Ave|District 13, B.C.|V3B 2Y8", + phone: "(250) 456-7944", + fax: "(250) 456-7945", + supportingDocuments: "Document 1|Document 2|Document 3", + districtId: 13, + concurrencyControlNumber: 1, + district: { + id: 13, + districtNumber: 13, + name: "District 13", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 13, + regionId: 5, + concurrencyControlNumber: 1, + region: { + id: 5, + name: "Region 5", + regionNumber: 5, + ministryRegionId: 5, + startDate: "1900-01-01T00:00:00Z", + endDate: null, + concurrencyControlNumber: 0 + } + } + }, + ], +}); \ No newline at end of file diff --git a/client/src/js/mock/api/getUserDistricts.js b/client/src/js/mock/api/getUserDistricts.js new file mode 100644 index 000000000..4e2e3aed1 --- /dev/null +++ b/client/src/js/mock/api/getUserDistricts.js @@ -0,0 +1,39 @@ +export const getUserDistricts = () => ({ + data: [ + { + id: 1231, + isPrimary: true, + userId: 123, + districtId: 1, + concurrencyControlNumber: 1, + district: { + id: 1, + districtNumber: 1, + name: "District 1", + startDate: "1900-01-01T00:00:00Z", + endDate: null, + ministryDistrictId: 1, + regionId: 3, + concurrencyControlNumber: 1, + region: null + }, + user: { + id: 123, + surname: "Name", + givenName: "My", + initials: null, + smUserId: "MNAME", + smAuthorizationDirectory: null, + guid: "123456AB789012C3456D78901EF2A3BC", + email: "my.name@gov.bc.ca", + agreementCity: "", + active: true, + districtId: 1, + concurrencyControlNumber: 2, + district: null, + userDistricts: [], + userRoles: [] + } + } + ], +}); \ No newline at end of file diff --git a/client/src/js/renderWithProviders.jsx b/client/src/js/renderWithProviders.jsx new file mode 100644 index 000000000..bc434cfcd --- /dev/null +++ b/client/src/js/renderWithProviders.jsx @@ -0,0 +1,19 @@ +import React from "react"; +import { render } from "@testing-library/react"; +import { Provider } from "react-redux"; + +import { setupStore } from "./store"; + +export const renderWithProviders = (ui, { + store = setupStore(), + ...renderOptions +} = {}) => { + const Wrapper = ({ children }) => ( + {children} + ); + + return { + store, + ...render(ui, { wrapper: Wrapper, ...renderOptions }), + }; +}; \ No newline at end of file diff --git a/client/src/js/store.js b/client/src/js/store.js index 122771de4..e9641ce31 100644 --- a/client/src/js/store.js +++ b/client/src/js/store.js @@ -18,18 +18,27 @@ if (process.env.NODE_ENV !== "production") { middleware.push(freeze); } -// Note passing middleware as the last argument to createStore requires redux@>=3.1.0 -const store = createStore( - allReducers, - composeEnhancers(applyMiddleware(...middleware)) -); +const setupStore = () => { + // Note passing middleware as the last argument to createStore requires redux@>=3.1.0 + const store = createStore( + allReducers, + composeEnhancers(applyMiddleware(...middleware)) + ); -if (process.env.NODE_ENV !== "production") { - if (module.hot) { - module.hot.accept("./reducers/all", () => - store.replaceReducer(require("./reducers/all").default) - ); + if (process.env.NODE_ENV !== "production") { + if (module.hot) { + module.hot.accept("./reducers/all", () => + store.replaceReducer(require("./reducers/all").default) + ); + } } -} -export default store; + return store; +}; + +const store = setupStore(); + +export { + store, + setupStore, +}; diff --git a/client/src/js/utils/http.js b/client/src/js/utils/http.js index ad6714e0b..dedf04f94 100644 --- a/client/src/js/utils/http.js +++ b/client/src/js/utils/http.js @@ -1,7 +1,6 @@ import _ from 'lodash'; import * as Action from '../actionTypes'; -import store from '../store'; import { keycloak } from '../Keycloak'; import * as Constant from '../constants'; @@ -9,20 +8,20 @@ import { resetSessionTimeoutTimer } from '../App'; var numRequestsInFlight = 0; -function incrementRequests() { +const incrementRequests = () => (dispatch) => { numRequestsInFlight += 1; if (numRequestsInFlight === 1) { - store.dispatch({ type: Action.REQUESTS_BEGIN }); + dispatch({ type: Action.REQUESTS_BEGIN }); } -} +}; -function decrementRequests() { +const decrementRequests = () => (dispatch) => { numRequestsInFlight -= 1; if (numRequestsInFlight <= 0) { numRequestsInFlight = 0; // sanity check; - store.dispatch({ type: Action.REQUESTS_END }); + dispatch({ type: Action.REQUESTS_END }); } -} +}; export const HttpError = function (msg, method, path, status, body) { this.message = msg || ''; @@ -64,7 +63,7 @@ Resource404.prototype = Object.create(Error.prototype, { }, }); -export async function request(path, options) { +export const request = (path, options) => async (dispatch) => { try { if (await keycloak.updateToken(5)) { //if token expires within 70 seconds it gets updated will return true to trigger resetSessionTimeoutTimer refresh. @@ -82,8 +81,8 @@ export async function request(path, options) { options.headers || {} ); - var xhr = new XMLHttpRequest(); - var method = (options.method || 'GET').toUpperCase(); + let xhr = new XMLHttpRequest(); + let method = (options.method || 'GET').toUpperCase(); if (!options.files) { options.headers = Object.assign( @@ -118,7 +117,7 @@ export async function request(path, options) { return new Promise((resolve, reject) => { xhr.addEventListener('load', function () { if (xhr.status >= 400) { - var responseText = ''; + let responseText = ''; try { responseText = xhr.responseText; } catch (e) { @@ -143,7 +142,7 @@ export async function request(path, options) { reject(new HttpError(`Request ${method} ${path} failed to send`, method, path)); }); - var qs = _.map(options.querystring, (value, key) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join( + let qs = _.map(options.querystring, (value, key) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join( '&' ); @@ -156,7 +155,7 @@ export async function request(path, options) { }); if (!options.silent) { - incrementRequests(); + dispatch(incrementRequests()); } var payload = options.body || null; @@ -176,13 +175,13 @@ export async function request(path, options) { xhr.send(payload); }).finally(() => { if (!options.silent) { - decrementRequests(); + dispatch(decrementRequests()); } }); } -export function jsonRequest(path, options) { - var jsonHeaders = { +export const jsonRequest = (path, options) => async (dispatch) => { + let jsonHeaders = { Accept: 'application/json', }; @@ -193,48 +192,48 @@ export function jsonRequest(path, options) { options.headers = Object.assign(options.headers || {}, jsonHeaders); - return request(path, options) - .then((xhr) => { - if (xhr.status === 204) { - return; - } else if (xhr.responseType === Constant.RESPONSE_TYPE_BLOB) { - return xhr.response; - } else if (options.ignoreResponse) { - return null; - } else { - return xhr.responseText ? JSON.parse(xhr.responseText) : null; + try { + const xhr = await dispatch(request(path, options)); + if (xhr.status === 204) { + return; + } + if (xhr.responseType === Constant.RESPONSE_TYPE_BLOB) { + return xhr.response; + } + if (options.ignoreResponse) { + return null; + } + return xhr.responseText ? JSON.parse(xhr.responseText) : null; + } catch (err) { + if (err instanceof HttpError) { + const errMsg = `API ${err.method} ${err.path} failed (${err.status})`; + let json = null; + let errorCode = null; + let errorDescription = null; + try { + // Example error payload from server: + // { + // "responseStatus": "ERROR", + // "data": null, + // "error": { + // "error": "HETS-01", + // "description": "Record not found" + // } + // } + + json = JSON.parse(err.body); + errorCode = json.error.error; + errorDescription = json.error.description; + } catch (err) { + /* not json */ } - }) - .catch((err) => { - if (err instanceof HttpError) { - var errMsg = `API ${err.method} ${err.path} failed (${err.status})`; - var json = null; - var errorCode = null; - var errorDescription = null; - try { - // Example error payload from server: - // { - // "responseStatus": "ERROR", - // "data": null, - // "error": { - // "error": "HETS-01", - // "description": "Record not found" - // } - // } - - json = JSON.parse(err.body); - errorCode = json.error.error; - errorDescription = json.error.description; - } catch (err) { - /* not json */ - } - throw new ApiError(errMsg, err.method, err.path, err.status, errorCode, errorDescription, json); - } else { - throw err; - } - }); -} + throw new ApiError(errMsg, err.method, err.path, err.status, errorCode, errorDescription, json); + } else { + throw err; + } + } +}; export function buildApiPath(path) { return `/api${path}`.replace('//', '/'); // remove double slashes @@ -246,41 +245,60 @@ export function ApiRequest(path, options) { } ApiRequest.prototype.get = function apiGet(params, options) { - return jsonRequest(this.path, { - method: 'GET', - querystring: params, - ...this.options, - ...options, - }); + const path = this.path; + const mainOptions = this.options; + return async function(dispatch) { + return await dispatch(jsonRequest(path, { + method: 'GET', + querystring: params, + ...mainOptions, + ...options, + })); + }; }; ApiRequest.prototype.getBlob = function apiGet() { - return request(this.path, { method: 'GET', responseType: 'blob' }); + const path = this.path; + return async function(dispatch) { + return await dispatch(request(path, { method: 'GET', responseType: 'blob' })); + }; }; ApiRequest.prototype.post = function apiPost(data, options) { - return jsonRequest(this.path, { - method: 'POST', - body: data, - ...this.options, - ...options, - }); + const path = this.path; + const mainOptions = this.options; + return async function(dispatch) { + return await dispatch(jsonRequest(path, { + method: 'POST', + body: data, + ...mainOptions, + ...options, + })); + }; }; ApiRequest.prototype.put = function apiPut(data, options) { - return jsonRequest(this.path, { - method: 'PUT', - body: data, - ...this.options, - ...options, - }); + const path = this.path; + const mainOptions = this.options; + return async function(dispatch) { + return await dispatch(jsonRequest(path, { + method: 'PUT', + body: data, + ...mainOptions, + ...options, + })); + }; }; ApiRequest.prototype.delete = function apiDelete(data, options) { - return jsonRequest(this.path, { - method: 'DELETE', - body: data, - ...this.options, - ...options, - }); + const path = this.path; + const mainOptions = this.options; + return async function(dispatch) { + return await dispatch(jsonRequest(path, { + method: 'DELETE', + body: data, + ...mainOptions, + ...options, + })); + }; }; diff --git a/client/src/js/views/AitReport.jsx b/client/src/js/views/AitReport.jsx index 23d43d441..220a770c8 100644 --- a/client/src/js/views/AitReport.jsx +++ b/client/src/js/views/AitReport.jsx @@ -9,7 +9,6 @@ import Moment from 'moment'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import PageHeader from '../components/ui/PageHeader.jsx'; import SearchBar from '../components/ui/SearchBar.jsx'; @@ -31,7 +30,7 @@ import { toZuluTime, dateIsBetween, } from '../utils/date'; -import { arrIntersection, hasArrsIntersect } from '../utils/set'; +import { arrIntersection, arrayToSet, setIntersection } from '../utils/set'; const THIS_FISCAL = 'This Fiscal'; const LAST_FISCAL = 'Last Fiscal'; @@ -54,8 +53,7 @@ class AitReport extends React.Component { constructor(props) { super(props); - - var today = Moment(); + const today = Moment(); this.state = { search: { @@ -71,13 +69,11 @@ class AitReport extends React.Component { sortField: props.ui.sortField || 'rentalAgreementNumber', sortDesc: props.ui.sortDesc === true, }, - }; - } buildSearchParams = () => { - var searchParams = { + const searchParams = { rentalAgreementNumber: this.state.search.rentalAgreementNumber || '', }; @@ -93,8 +89,8 @@ class AitReport extends React.Component { searchParams.equipment = this.state.search.equipmentIds; } - var startDate = Moment(this.state.search.startDate); - var endDate = Moment(this.state.search.endDate); + const startDate = Moment(this.state.search.startDate); + const endDate = Moment(this.state.search.endDate); if (startDate && startDate.isValid()) { searchParams.startDate = toZuluTime(startDate.startOf('day')); @@ -107,16 +103,14 @@ class AitReport extends React.Component { }; componentDidMount() { - Api.getRentalAgreementSummaryLite(); - Api.getProjectsAgreementSummary(); - Api.getDistrictEquipmentTypesAgreementSummary(); - Api.getEquipmentAgreementSummary(); - - + this.props.dispatch(Api.getRentalAgreementSummaryLite()); + this.props.dispatch(Api.getProjectsAgreementSummary()); + this.props.dispatch(Api.getDistrictEquipmentTypesAgreementSummary()); + this.props.dispatch(Api.getEquipmentAgreementSummary()); // If this is the first load, then look for a default favourite if (_.isEmpty(this.props.search)) { - var defaultFavourite = _.find(this.props.favourites, (f) => f.isDefault); + const defaultFavourite = _.find(this.props.favourites, (f) => f.isDefault); if (defaultFavourite) { this.loadFavourite(defaultFavourite); } @@ -124,7 +118,7 @@ class AitReport extends React.Component { } fetch = () => { - Api.searchAitReport(this.buildSearchParams()); + this.props.dispatch(Api.searchAitReport(this.buildSearchParams())); }; search = (e) => { @@ -133,9 +127,9 @@ class AitReport extends React.Component { }; clearSearch = () => { - var today = Moment(); + const today = Moment(); - var defaultSearchParameters = { + const defaultSearchParameters = { projectIds: [], districtEquipmentTypes: [], equipmentIds: [], @@ -146,22 +140,14 @@ class AitReport extends React.Component { }; this.setState({ search: defaultSearchParameters }, () => { - store.dispatch({ - type: Action.UPDATE_AIT_SEARCH, - aitResponses: this.state.search, - }); - store.dispatch({ type: Action.CLEAR_AIT_REPORT }); + this.props.updateAitSearch(this.state.search); + this.props.clearAitReport(); }); }; - - updateSearchState = (state, callback) => { this.setState({ search: { ...this.state.search, ...state, ...{ loaded: true } } }, () => { - store.dispatch({ - type: Action.UPDATE_AIT_SEARCH, - aitResponses: this.state.search, - }); + this.props.updateAitSearch(this.state.search); if (callback) { callback(); } @@ -170,10 +156,7 @@ class AitReport extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ - type: Action.UPDATE_AIT_REPORT_UI, - aitResponses: this.state.ui, - }); + this.props.updateAitReportUi(this.state.ui); if (callback) { callback(); } @@ -193,8 +176,8 @@ class AitReport extends React.Component { return No results; } - var aitResponses = _.sortBy(this.props.aitResponses.data, (response) => { - var sortValue = response[this.state.ui.sortField]; + let aitResponses = _.sortBy(this.props.aitResponses.data, (response) => { + const sortValue = response[this.state.ui.sortField]; if (typeof sortValue === 'string') { return sortValue.toLowerCase(); } @@ -243,36 +226,20 @@ class AitReport extends React.Component { ); }; - getMatchedAgreementIds = () => { + getAgreementIdsWithinDateRange = () => { const startDate = Moment(this.state.search.startDate); const endDate = Moment(this.state.search.endDate); return _.chain(this.props.agreementSummaryLite.data) - .filter((a) => dateIsBetween(Moment(a.datedOn), startDate, endDate)) + .filter((agreement) => dateIsBetween(Moment(agreement.datedOn), startDate, endDate)) .map('id') .value(); }; - matchesProjectFilter = (projectIds) => { - if (this.state.search.projectIds.length === 0) { - return true; - } - - return hasArrsIntersect(this.state.search.projectIds, projectIds); - }; - - matchesDistrictEquipmentTypeFilter = (districtEquipmentTypeId) => { - if (this.state.search.districtEquipmentTypes.length === 0) { - return true; - } - - return _.includes(this.state.search.districtEquipmentTypes, districtEquipmentTypeId); - }; - updateDateRangeSearchState = (state) => { - var today = Moment(); - var startDate; - var endDate; + const today = Moment(); + let startDate; + let endDate; switch (state.dateRange) { case THIS_FISCAL: // Fiscal Year: Apr 1 - March 31 @@ -307,74 +274,86 @@ class AitReport extends React.Component { }; updateProjectSearchState = (searchState) => { - this.updateSearchState(searchState, this.filterSelectedEquipmentType); + this.updateSearchState(searchState, () => { + const availableProjectIds = this.getFilteredProjects().map(project => project.id); + this.filterSelectedEquipmentType(availableProjectIds); + }); }; updateEquipmentTypeSearchState = (searchState) => { - this.updateSearchState(searchState, this.filterSelectedEquipment); + this.updateSearchState(searchState, () => { + const availableProjectIds = this.getFilteredProjects().map(project => project.id); + const availableEquipmentTypeIds = this.getFilteredDistrictEquipmentType(availableProjectIds).map(eqType => eqType.id); + this.filterSelectedEquipment(availableProjectIds, availableEquipmentTypeIds); + }); }; filterSelectedProjects = () => { - var acceptableProjects = _.map(this.getFilteredProjects(), 'id'); - var projectIds = arrIntersection(this.state.search.projectIds, acceptableProjects); - this.updateSearchState({ - projectIds: projectIds - }, this.filterSelectedEquipmentType); + const availableProjects = _.map(this.getFilteredProjects(), 'id'); + const projectIds = arrIntersection(this.state.search.projectIds, availableProjects); + this.updateSearchState({ projectIds }, () => this.filterSelectedEquipmentType(availableProjects)); }; - filterSelectedEquipmentType = () => { - var acceptableDistrictEquipmentTypes = _.map(this.getFilteredDistrictEquipmentType(), 'id'); - var districtEquipmentTypes = arrIntersection( - this.state.search.districtEquipmentTypes, - acceptableDistrictEquipmentTypes - ); - this.updateSearchState({ - districtEquipmentTypes: districtEquipmentTypes - }, this.filterSelectedEquipment); + filterSelectedEquipmentType = (availableProjectIds) => { + const availableEquipmentTypes = _.map(this.getFilteredDistrictEquipmentType(availableProjectIds), 'id'); + const districtEquipmentTypes = arrIntersection(this.state.search.districtEquipmentTypes, availableEquipmentTypes); + this.updateSearchState({ districtEquipmentTypes }, () => this.filterSelectedEquipment(availableProjectIds, availableEquipmentTypes)); }; - filterSelectedEquipment = () => { - var acceptableEquipmentIds = _.map(this.getFilteredEquipment(), 'id'); - var equipmentIds = arrIntersection(this.state.search.equipmentIds, acceptableEquipmentIds); - this.updateSearchState({ equipmentIds: equipmentIds }); + filterSelectedEquipment = (availableProjectIds, availableEquipmentTypeIds) => { + const availableEquipmentIds = _.map(this.getFilteredEquipment(availableProjectIds, availableEquipmentTypeIds), 'id'); + const equipmentIds = arrIntersection(this.state.search.equipmentIds, availableEquipmentIds); + this.updateSearchState({ equipmentIds }); }; getFilteredProjects = () => { - const matchedAgreementIds = this.getMatchedAgreementIds(); + const availableAgreementIdSet = arrayToSet(this.getAgreementIdsWithinDateRange()); + return _.chain(this.props.projects.data) - .filter((project) => hasArrsIntersect(project.agreementIds, matchedAgreementIds)) - .sortBy('name') + .filter(project => setIntersection(arrayToSet(project.agreementIds), availableAgreementIdSet).size > 0) + .uniqBy("id") + .sortBy("name") .value(); }; - getFilteredDistrictEquipmentType = () => { - const matchedAgreementIds = this.getMatchedAgreementIds(); + getFilteredDistrictEquipmentType = (availableProjectIds) => { + const availableAgreementIdSet = arrayToSet(this.getAgreementIdsWithinDateRange()); + const availableProjectIdSet = this.state.search.projectIds.length === 0 ? + arrayToSet(availableProjectIds) : arrayToSet(this.state.search.projectIds); + return _.chain(this.props.districtEquipmentTypes.data) - .filter(equipmentType => hasArrsIntersect(equipmentType.agreementIds, matchedAgreementIds)) - .filter(equipmentType => this.matchesProjectFilter(equipmentType.projectIds)) + .filter(equipmentType => + setIntersection(arrayToSet(equipmentType.agreementIds), availableAgreementIdSet).size > 0 && + setIntersection(arrayToSet(equipmentType.projectIds), availableProjectIdSet).size > 0) + .uniqBy("id") .sortBy('name') .value(); }; - getFilteredEquipment = () => { - const matchedAgreementIds = this.getMatchedAgreementIds(); + getFilteredEquipment = (availableProjectIds, availableEquipmentTypeIds) => { + const availableAgreementIdSet = arrayToSet(this.getAgreementIdsWithinDateRange()); + const availableProjectIdSet = this.state.search.projectIds.length === 0 ? + arrayToSet(availableProjectIds) : arrayToSet(this.state.search.projectIds); + const availableEquipmentTypeIdSet = this.state.search.districtEquipmentTypes.length === 0 ? + arrayToSet(availableEquipmentTypeIds) : arrayToSet(this.state.search.districtEquipmentTypes); + return _.chain(this.props.equipment.data) - .filter(equipment => hasArrsIntersect(equipment.agreementIds, matchedAgreementIds)) - .filter(equipment => this.matchesProjectFilter(equipment.projectIds)) - .filter(equipment => this.matchesDistrictEquipmentTypeFilter(equipment.districtEquipmentTypeId)) + .filter(equipment => + setIntersection(arrayToSet(equipment.agreementIds), availableAgreementIdSet).size > 0 && + setIntersection(arrayToSet(equipment.projectIds), availableProjectIdSet).size > 0 && + availableEquipmentTypeIdSet.has(equipment.districtEquipmentTypeId)) + .uniqBy("id") .sortBy('equipmentCode') .value(); }; render() { - var resultCount = ''; - if (this.props.aitResponses.loaded) { - resultCount = '(' + Object.keys(this.props.aitResponses.data).length + ')'; - } - - var projects = this.getFilteredProjects(); - var districtEquipmentTypes = this.getFilteredDistrictEquipmentType(); - var equipment = this.getFilteredEquipment(); + const resultCount = this.props.aitResponses.loaded ? `(${Object.keys(this.props.aitResponses.data).length})` : ''; + const projects = this.getFilteredProjects(); + const projectIds = projects.map(project => project.id); + const districtEquipmentTypes = this.getFilteredDistrictEquipmentType(projectIds); + const equipmentTypeIds = districtEquipmentTypes.map(eqType => eqType.id); + const equipments = this.getFilteredEquipment(projectIds, equipmentTypeIds); return (
@@ -412,7 +391,7 @@ class AitReport extends React.Component { id="equipmentIds" placeholder="Equipment" fieldName="equipmentCode" - items={equipment} + items={equipments} disabled={!this.props.equipment.loaded} selectedIds={this.state.search.equipmentIds} updateState={this.updateSearchState} @@ -498,22 +477,35 @@ class AitReport extends React.Component { } } -function mapStateToProps(state) { - - - var result = { - currentUser: state.user, - agreementSummaryLite: state.lookups.agreementSummaryLite, - projects: state.lookups.projectsAgreementSummary, - districtEquipmentTypes: state.lookups.districtEquipmentTypesAgreementSummary, - equipment: state.lookups.equipment.agreementSummary, - aitResponses: state.models.aitResponses, - favourites: state.models.favourites.aitReport, - search: state.search.aitResponses, - ui: state.ui.aitResponses, - }; - - return result; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + agreementSummaryLite: state.lookups.agreementSummaryLite, + projects: state.lookups.projectsAgreementSummary, + districtEquipmentTypes: state.lookups.districtEquipmentTypesAgreementSummary, + equipment: state.lookups.equipment.agreementSummary, + aitResponses: state.models.aitResponses, + favourites: state.models.favourites.aitReport, + search: state.search.aitResponses, + ui: state.ui.aitResponses, +}); + +const mapDispatchToProps = (dispatch) => ({ + updateAitSearch: (search) => { + dispatch({ + type: Action.UPDATE_AIT_SEARCH, + aitResponses: search, + }); + }, + clearAitReport: () => { + dispatch({ type: Action.CLEAR_AIT_REPORT }); + }, + updateAitReportUi: (ui) => { + dispatch({ + type: Action.UPDATE_AIT_REPORT_UI, + aitResponses: ui, + }); + }, + dispatch, +}); -export default connect(mapStateToProps)(AitReport); \ No newline at end of file +export default connect(mapStateToProps, mapDispatchToProps)(AitReport); \ No newline at end of file diff --git a/client/src/js/views/AitReport.test.jsx b/client/src/js/views/AitReport.test.jsx new file mode 100644 index 000000000..4824cb6d7 --- /dev/null +++ b/client/src/js/views/AitReport.test.jsx @@ -0,0 +1,262 @@ +import { rest } from "msw"; +import { setupServer } from "msw/lib/node"; +import Moment from "moment"; + +import { setupStore } from "../store"; +import * as Action from "../actionTypes"; +import { dateIsBetween, endOfCurrentFiscal, endOfPreviousFiscal, startOfCurrentFiscal, startOfPreviousFiscal } from "../utils/date"; +import { getProjects } from "../mock/api/AitReport/getProjects"; +import { getEquipments } from "../mock/api/AitReport/getEquipments"; +import { getEquipmentTypes } from "../mock/api/AitReport/getEquipmentTypes"; +import { getRentalAgreementsLite } from "../mock/api/AitReport/getRentalAgreementsLite"; +import { searchAitReport } from "../mock/api/AitReport/searchAitReport"; +import { keycloak } from "../Keycloak"; +import { renderWithProviders } from "../renderWithProviders"; +import AitReport from "./AitReport"; +import { screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { getCurrentUser } from "../mock/api/getCurrentUser"; +import { arrayToSet, hasArrsIntersect } from "../utils/set"; +import { setToArray } from "../utils/set"; + +// Mock Keycloak service +const mockKeycloakUpdateToken = jest.spyOn(keycloak, "updateToken"); +mockKeycloakUpdateToken.mockResolvedValue(Promise.resolve(false)); + +const getStartCurrFiscal = () => { + const currDateTime = Moment(); + return startOfCurrentFiscal(currDateTime); +}; + +const getEndCurrFiscal = () => { + const currDateTime = Moment(); + return endOfCurrentFiscal(currDateTime); +}; + +const getStartLastFiscal = () => { + const currDateTime = Moment(); + return startOfPreviousFiscal(currDateTime); +}; + +const getEndLastFiscal = () => { + const currDateTime = Moment(); + return endOfPreviousFiscal(currDateTime); +}; + +const server = setupServer( + rest.get("/api/projects/agreementSummary", async (_, res, ctx) => { + return res(ctx.json(getProjects())); + }), + rest.get("/api/equipment/agreementSummary", async (_, res, ctx) => { + return res(ctx.json(getEquipments())); + }), + rest.get("/api/districtequipmenttypes/agreementSummary", async (_, res, ctx) => { + return res(ctx.json(getEquipmentTypes())); + }), + rest.get("/api/rentalagreements/summaryLite", async (_, res, ctx) => { + return res(ctx.json(getRentalAgreementsLite(getStartCurrFiscal()))); + }), + rest.get("/api/rentalAgreements/aitReport", async (_, res, ctx) => { + return res(ctx.json(searchAitReport(getStartCurrFiscal()))); + }), +); + +let store; + +beforeAll(() => { + server.listen(); +}); + +beforeEach(() => { + store = setupStore(); + const authorizedUser = getCurrentUser().data; + authorizedUser.hasPermission = (_) => true; + + store.dispatch({ + type: Action.UPDATE_CURRENT_USER, + user: authorizedUser, + }); +}) + +afterEach(() => { + server.resetHandlers(); +}); + +afterAll(() => { + server.close(); +}); + +describe("AitReport rendering filters", () => { + test("AitReport renders date filters correctly", async () => { + const user = userEvent.setup(); + renderWithProviders(, { store }); + + await waitFor(() => { + expect(store.getState().lookups.agreementSummaryLite.data).not.toEqual({}); + }); + + const dateFilterBtn = await screen.findByText(/This Fiscal/i); + await user.click(dateFilterBtn); + + const thisFiscalSels = await screen.findAllByText(/This Fiscal/i); + expect(thisFiscalSels).toHaveLength(2); + const lastFiscalSel = await screen.findByText(/Last Fiscal/i); + expect(lastFiscalSel).not.toBeNull(); + const customDateFilterSel = await screen.findByText(/Custom/i); + expect(customDateFilterSel).not.toBeNull(); + }); + + test("Other filters render correctly with This Fiscal date filter", async () => { + const user = userEvent.setup(); + renderWithProviders(, { store }); + + const dateFilterBtn = await screen.findByText(/This Fiscal/i); + await user.click(dateFilterBtn); + + const startCurrFiscal = getStartCurrFiscal(); + const endCurrFiscal = getEndCurrFiscal(); + const agreementIds = getRentalAgreementsLite(startCurrFiscal).data + .filter(agreement => dateIsBetween(Moment.utc(agreement.datedOn), Moment.utc(startCurrFiscal), Moment.utc(endCurrFiscal))) + .map(agreement => agreement.id); + + const projects = getProjects().data.filter(proj => hasArrsIntersect(proj.agreementIds, agreementIds)); + const projectIds = setToArray(arrayToSet(projects.map(proj => proj.id))); + const equipmentTypes = getEquipmentTypes().data + .filter(eqType => hasArrsIntersect(eqType.agreementIds, agreementIds)); + const equipmentTypeIds = setToArray(arrayToSet(equipmentTypes.map(eqType => eqType.id))); + const equipments = getEquipments().data + .filter(eq => hasArrsIntersect(eq.agreementIds, agreementIds)); + const equipmentIds = setToArray(arrayToSet(equipments.map(equipment => equipment.id))); + + const projectsBtn = screen.getByText(/Projects/i); + await user.click(projectsBtn); + expect(screen.queryAllByText(/Test Project \d+/i)).toHaveLength(projectIds.length); + + const equipmentTypesBtn = screen.getByText(/Equipment Types/i); + await user.click(equipmentTypesBtn); + expect(screen.queryAllByText(/Eq Type \d+/i)).toHaveLength(equipmentTypeIds.length); + + const equipmentsBtn = screen.getByText("Equipment"); + await user.click(equipmentsBtn); + expect(screen.queryAllByText(/EC\d+/i)).toHaveLength(equipmentIds.length); + }); + + test("Other filters render correctly with Last Fiscal date filter", async () => { + const user = userEvent.setup(); + renderWithProviders(, { store }); + + const dateFilterBtn = await screen.findByText(/This Fiscal/i); + await user.click(dateFilterBtn); + const lastFiscalOption = screen.getByText(/Last Fiscal/i); + await user.click(lastFiscalOption); + + const startCurrFiscal = getStartCurrFiscal(); + const startPrevFiscal = getStartLastFiscal(); + const endPrevFiscal = getEndLastFiscal(); + const agreementIds = getRentalAgreementsLite(startCurrFiscal).data + .filter(agreement => dateIsBetween(Moment(agreement.datedOn), Moment(startPrevFiscal), Moment(endPrevFiscal))) + .map(agreement => agreement.id); + + const projects = getProjects().data + .filter(proj => hasArrsIntersect(proj.agreementIds, agreementIds)); + const projectIds = setToArray(arrayToSet(projects.map(proj => proj.id))); + const equipmentTypes = getEquipmentTypes().data + .filter(eqType => + hasArrsIntersect(eqType.agreementIds, agreementIds) && + hasArrsIntersect(eqType.projectIds, projectIds)); + const equipmentTypeIds = setToArray(arrayToSet(equipmentTypes.map(eqType => eqType.id))); + const equipments = getEquipments().data + .filter(eq => + hasArrsIntersect(eq.agreementIds, agreementIds) && + hasArrsIntersect(eq.projectIds, projectIds) && + equipmentTypeIds.includes(eq.districtEquipmentTypeId)); + const equipmentIds = setToArray(arrayToSet(equipments.map(equipment => equipment.id))); + + const projectsBtn = screen.getByText(/Projects/i); + await user.click(projectsBtn); + expect(screen.queryAllByText(/Test Project \d+/i)).toHaveLength(projectIds.length); + + const equipmentTypesBtn = screen.getByText(/Equipment Types/i); + await user.click(equipmentTypesBtn); + expect(screen.queryAllByText(/Eq Type \d+/i)).toHaveLength(equipmentTypeIds.length); + + const equipmentsBtn = screen.getByText("Equipment"); + await user.click(equipmentsBtn); + expect(screen.queryAllByText(/EC\d+/i)).toHaveLength(equipmentIds.length); + }); + + test("Other filters render correctly with Custom date filter", async () => { + const user = userEvent.setup(); + renderWithProviders(, { store }); + + const dateFilterBtn = await screen.findByText(/This Fiscal/i); + await user.click(dateFilterBtn); + const customDateOption = await screen.findByText(/Custom/i); + await user.click(customDateOption); + + const startCurrFiscal = getStartCurrFiscal(); + const startPrevFiscal = getStartLastFiscal(); + const endPrevFiscal = getEndLastFiscal(); + const now = Moment(); + const nowDateStr = Moment(now).format("YYYY-MM-DD"); + + const dateFromInput = screen.getAllByDisplayValue(nowDateStr)[0]; + await user.click(dateFromInput); + await user.pointer([{target: dateFromInput, offset: 0, keys: '[MouseLeft>]'}, {offset: 10}]); + await user.paste(Moment(startPrevFiscal).format("YYYY-MM-DD")); + + expect(dateFromInput).toHaveValue(Moment(startPrevFiscal).format("YYYY-MM-DD")); + + const dateToInput = screen.getAllByDisplayValue(nowDateStr)[0]; + await user.click(dateToInput); + await user.pointer([{target: dateToInput, offset: 0, keys: '[MouseLeft>]'}, {offset: 10}]); + await user.paste(Moment(endPrevFiscal).format("YYYY-MM-DD")); + + expect(dateToInput).toHaveValue(Moment(endPrevFiscal).format("YYYY-MM-DD")); + + const agreementIds = getRentalAgreementsLite(startCurrFiscal).data + .filter(agreement => dateIsBetween(Moment(agreement.datedOn), Moment(startPrevFiscal), Moment(endPrevFiscal))) + .map(agreement => agreement.id); + + const projects = getProjects().data + .filter(proj => hasArrsIntersect(proj.agreementIds, agreementIds)); + const projectIds = setToArray(arrayToSet(projects.map(proj => proj.id))); + const equipmentTypes = getEquipmentTypes().data + .filter(eqType => + hasArrsIntersect(eqType.agreementIds, agreementIds) && + hasArrsIntersect(eqType.projectIds, projectIds)); + const equipmentTypeIds = setToArray(arrayToSet(equipmentTypes.map(eqType => eqType.id))); + const equipments = getEquipments().data + .filter(eq => + hasArrsIntersect(eq.agreementIds, agreementIds) && + hasArrsIntersect(eq.projectIds, projectIds) && + equipmentTypeIds.includes(eq.districtEquipmentTypeId)); + const equipmentIds = setToArray(arrayToSet(equipments.map(equipment => equipment.id))); + + const projectsBtn = screen.getByText(/Projects/i); + await user.click(projectsBtn); + expect(screen.queryAllByText(/Test Project \d+/i)).toHaveLength(projectIds.length); + + const equipmentTypesBtn = screen.getByText(/Equipment Types/i); + await user.click(equipmentTypesBtn); + expect(screen.queryAllByText(/Eq Type \d+/i)).toHaveLength(equipmentTypeIds.length); + + const equipmentsBtn = screen.getByText("Equipment"); + await user.click(equipmentsBtn); + expect(screen.queryAllByText(/EC\d+/i)).toHaveLength(equipmentIds.length); + }); +}); + +describe("AitReport filter behaviour", () => { + test("Other filters update correctly with changing date filter", () => { + // + }); + + test("Other filters update correctly with changing project filter", () => { + // + }); + + test("Other filters update correctly with changing equipment type filter", () => { + // + }); +}); diff --git a/client/src/js/views/BusinessOwner.jsx b/client/src/js/views/BusinessOwner.jsx index 93f67ef3d..a46eca196 100644 --- a/client/src/js/views/BusinessOwner.jsx +++ b/client/src/js/views/BusinessOwner.jsx @@ -8,7 +8,6 @@ import _ from 'lodash'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import Spinner from '../components/Spinner.jsx'; import ColDisplay from '../components/ColDisplay.jsx'; @@ -57,7 +56,7 @@ class BusinessOwner extends React.Component { } componentDidMount() { - store.dispatch({ + this.props.dispatch({ type: Action.SET_ACTIVE_OWNER_ID_UI, ownerId: this.props.match.params.ownerId, }); @@ -74,9 +73,9 @@ class BusinessOwner extends React.Component { } fetch = () => { - var ownerId = this.props.match.params.ownerId; + const ownerId = this.props.match.params.ownerId; - return Api.getOwnerForBusiness(ownerId) + return this.props.dispatch(Api.getOwnerForBusiness(ownerId)) .then(() => { this.setState({ success: true }); }) @@ -86,8 +85,9 @@ class BusinessOwner extends React.Component { }; updateContactsUIState = (state, callback) => { + const dispatch = this.props.dispatch; this.setState({ uiContacts: { ...this.state.uiContacts, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_OWNER_CONTACTS_UI, ownerContacts: this.state.uiContacts }); + dispatch({ type: Action.UPDATE_OWNER_CONTACTS_UI, ownerContacts: this.state.uiContacts }); if (callback) { callback(); } @@ -95,8 +95,9 @@ class BusinessOwner extends React.Component { }; updateEquipmentUIState = (state, callback) => { + const dispatch = this.props.dispatch; this.setState({ uiEquipment: { ...this.state.uiEquipment, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_OWNER_EQUIPMENT_UI, ownerEquipment: this.state.uiEquipment }); + dispatch({ type: Action.UPDATE_OWNER_EQUIPMENT_UI, ownerEquipment: this.state.uiEquipment }); if (callback) { callback(); } @@ -377,12 +378,12 @@ class BusinessOwner extends React.Component { }; } -function mapStateToProps(state) { - return { - owner: activeOwnerSelector(state), - uiEquipment: state.ui.ownerEquipment, - uiContacts: state.ui.ownerContacts, - }; -} +const mapStateToProps = (state) => ({ + owner: activeOwnerSelector(state), + uiEquipment: state.ui.ownerEquipment, + uiContacts: state.ui.ownerContacts, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(BusinessOwner); +export default connect(mapStateToProps, mapDispatchToProps)(BusinessOwner); diff --git a/client/src/js/views/BusinessPortal.jsx b/client/src/js/views/BusinessPortal.jsx index 1810293dd..c2794d7ec 100644 --- a/client/src/js/views/BusinessPortal.jsx +++ b/client/src/js/views/BusinessPortal.jsx @@ -8,7 +8,6 @@ import _ from 'lodash'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import PageHeader from '../components/ui/PageHeader.jsx'; import Spinner from '../components/Spinner.jsx'; @@ -55,7 +54,7 @@ class BusinessPortal extends React.Component { } fetch = () => { - return Api.getBusiness().then(() => { + return this.props.dispatch(Api.getBusiness()).then(() => { this.setState({ success: !_.isEmpty(this.props.business) }); }); }; @@ -65,8 +64,9 @@ class BusinessPortal extends React.Component { }; updateOwnersUIState = (state, callback) => { + const dispatch = this.props.dispatch; this.setState({ uiOwners: { ...this.state.uiOwners, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_OWNERS_UI, owners: this.state.uiOwners }); + dispatch({ type: Action.UPDATE_OWNERS_UI, owners: this.state.uiOwners }); if (callback) { callback(); } @@ -81,7 +81,7 @@ class BusinessPortal extends React.Component { e.persist(); this.setState({ validating: true, errors: {} }); - Api.validateOwner(this.state.secretKey, this.state.postalCode) + this.props.dispatch(Api.validateOwner(this.state.secretKey, this.state.postalCode)) .then(() => { debugger; // clear input fields @@ -265,12 +265,12 @@ class BusinessPortal extends React.Component { }; } -function mapStateToProps(state) { - return { - user: state.user, - business: state.models.business, - uiOwners: state.ui.owners, - }; -} +const mapStateToProps = (state) => ({ + user: state.user, + business: state.models.business, + uiOwners: state.ui.owners, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(BusinessPortal); +export default connect(mapStateToProps, mapDispatchToProps)(BusinessPortal); diff --git a/client/src/js/views/DistrictAdmin.jsx b/client/src/js/views/DistrictAdmin.jsx index ee992e27d..7836841d9 100644 --- a/client/src/js/views/DistrictAdmin.jsx +++ b/client/src/js/views/DistrictAdmin.jsx @@ -54,8 +54,8 @@ class DistrictAdmin extends React.Component { } componentDidMount() { - Api.getRentalConditions(); - Api.getDistrictEquipmentTypes(); + this.props.dispatch(Api.getRentalConditions()); + this.props.dispatch(Api.getDistrictEquipmentTypes()); } updateEquipmentUIState = (state, callback) => { @@ -75,10 +75,10 @@ class DistrictAdmin extends React.Component { this.setState({ condition: condition }, this.showConditionAddEditDialog); }; - deleteCondition = (condition) => { - Api.deleteCondition(condition.id).then(() => { - Api.getRentalConditions(); - }); + deleteCondition = async (condition) => { + const dispatch = this.props.dispatch; + await dispatch(Api.deleteCondition(condition.id)); + dispatch(Api.getRentalConditions()); }; showConditionAddEditDialog = () => { @@ -98,7 +98,7 @@ class DistrictAdmin extends React.Component { }; conditionSaved = () => { - Api.getRentalConditions(); + this.props.dispatch(Api.getRentalConditions()); }; showDistrictEquipmentTypeAddEditDialog = () => { @@ -122,24 +122,25 @@ class DistrictAdmin extends React.Component { }; districtEquipmentTypeSaved = () => { - Api.getDistrictEquipmentTypes(); + this.props.dispatch(Api.getDistrictEquipmentTypes()); }; - deleteDistrictEquipmentType = (equipment) => { - Api.deleteDistrictEquipmentType(equipment) - .then(() => { - return Api.getDistrictEquipmentTypes(); - }) - .catch((error) => { - if (error.status === 400 && error.errorCode === 'HETS-37') { - this.setState({ - showDistrictEquipmentTypeErrorDialog: true, - districtEquipmentTypeError: error.errorDescription, - }); - } else { - throw error; - } - }); + deleteDistrictEquipmentType = async (equipment) => { + const dispatch = this.props.dispatch; + + try { + await dispatch(Api.deleteDistrictEquipmentType(equipment)); + dispatch(Api.getDistrictEquipmentTypes()); + } catch(error) { + if (error.status === 400 && error.errorCode === 'HETS-37') { + this.setState({ + showDistrictEquipmentTypeErrorDialog: true, + districtEquipmentTypeError: error.errorDescription, + }); + } else { + throw error; + } + } }; render() { @@ -380,14 +381,14 @@ class DistrictAdmin extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - rentalConditions: state.lookups.rentalConditions, - districtEquipmentTypes: state.lookups.districtEquipmentTypes, - equipmentTypes: state.lookups.equipmentTypes, - uiEquipment: state.ui.districtEquipment, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + rentalConditions: state.lookups.rentalConditions, + districtEquipmentTypes: state.lookups.districtEquipmentTypes, + equipmentTypes: state.lookups.equipmentTypes, + uiEquipment: state.ui.districtEquipment, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(DistrictAdmin); +export default connect(mapStateToProps, mapDispatchToProps)(DistrictAdmin); diff --git a/client/src/js/views/Equipment.jsx b/client/src/js/views/Equipment.jsx index 3d0959862..ecbce2f1e 100644 --- a/client/src/js/views/Equipment.jsx +++ b/client/src/js/views/Equipment.jsx @@ -8,7 +8,6 @@ import Moment from 'moment'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import PageHeader from '../components/ui/PageHeader.jsx'; import SearchBar from '../components/ui/SearchBar.jsx'; @@ -109,7 +108,7 @@ class Equipment extends React.Component { }; componentDidMount() { - Api.getDistrictEquipmentTypes(); + this.props.dispatch(Api.getDistrictEquipmentTypes()); // If this is the first load, then look for a default favourite if (_.isEmpty(this.props.search)) { @@ -121,7 +120,7 @@ class Equipment extends React.Component { } fetch = () => { - Api.searchEquipmentList(this.buildSearchParams()); + this.props.dispatch(Api.searchEquipmentList(this.buildSearchParams())); }; search = (e) => { @@ -144,17 +143,17 @@ class Equipment extends React.Component { }; this.setState({ search: defaultSearchParameters }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_EQUIPMENT_LIST_SEARCH, equipmentList: this.state.search, }); - store.dispatch({ type: Action.CLEAR_EQUIPMENT_LIST }); + this.props.dispatch({ type: Action.CLEAR_EQUIPMENT_LIST }); }); }; updateSearchState = (state, callback) => { this.setState({ search: { ...this.state.search, ...state } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_EQUIPMENT_LIST_SEARCH, equipmentList: this.state.search, }); @@ -166,7 +165,7 @@ class Equipment extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_EQUIPMENT_LIST_UI, equipmentList: this.state.ui, }); @@ -360,16 +359,16 @@ class Equipment extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - equipmentList: state.models.equipmentList, - localAreas: state.lookups.localAreas, - districtEquipmentTypes: state.lookups.districtEquipmentTypes, - favourites: state.models.favourites.equipment, - search: state.search.equipmentList, - ui: state.ui.equipmentList, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + equipmentList: state.models.equipmentList, + localAreas: state.lookups.localAreas, + districtEquipmentTypes: state.lookups.districtEquipmentTypes, + favourites: state.models.favourites.equipment, + search: state.search.equipmentList, + ui: state.ui.equipmentList, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(Equipment); +export default connect(mapStateToProps, mapDispatchToProps)(Equipment); diff --git a/client/src/js/views/EquipmentDetail.jsx b/client/src/js/views/EquipmentDetail.jsx index b24f8e702..8a57584c2 100644 --- a/client/src/js/views/EquipmentDetail.jsx +++ b/client/src/js/views/EquipmentDetail.jsx @@ -19,7 +19,6 @@ import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; import * as Log from '../history'; -import store from '../store'; import BadgeLabel from '../components/BadgeLabel.jsx'; import ColDisplay from '../components/ColDisplay.jsx'; @@ -88,16 +87,16 @@ class EquipmentDetail extends React.Component { } componentDidMount() { - store.dispatch({ + this.props.dispatch({ type: Action.SET_ACTIVE_EQUIPMENT_ID_UI, equipmentId: this.props.match.params.equipmentId, }); - let equipmentId = this.props.match.params.equipmentId; + const equipmentId = this.props.match.params.equipmentId; // Notes and documents need be fetched every time as they are not equipment-specific in the store ATM - Api.getEquipmentNotes(equipmentId).then(() => this.setState({ loadingNotes: false })); - Api.getEquipmentDocuments(equipmentId).then(() => this.setState({ loadingDocuments: false })); + this.props.dispatch(Api.getEquipmentNotes(equipmentId)).then(() => this.setState({ loadingNotes: false })); + this.props.dispatch(Api.getEquipmentDocuments(equipmentId)).then(() => this.setState({ loadingDocuments: false })); // Re-fetch equipment every time Promise.all([this.fetch()]).then(() => { @@ -107,7 +106,8 @@ class EquipmentDetail extends React.Component { fetch = () => { this.setState({ reloading: true }); - return Api.getEquipment(this.props.match.params.equipmentId).then(() => this.setState({ reloading: false })); + return this.props.dispatch(Api.getEquipment(this.props.match.params.equipmentId)) + .then(() => this.setState({ reloading: false })); }; showNotes = () => { @@ -128,7 +128,7 @@ class EquipmentDetail extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_PHYSICAL_ATTACHMENTS_UI, equipmentPhysicalAttachments: this.state.ui, }); @@ -162,7 +162,7 @@ class EquipmentDetail extends React.Component { onStatusChanged = () => { this.closeChangeStatusDialog(); - Api.getEquipmentNotes(this.props.equipment.id); + this.props.dispatch(Api.getEquipmentNotes(this.props.equipment.id)); }; openSeniorityDialog = () => { @@ -185,7 +185,7 @@ class EquipmentDetail extends React.Component { physicalAttachmentsAdded = () => { var equipId = this.props.match.params.equipmentId; - Api.getEquipment(equipId); + this.props.dispatch(Api.getEquipment(equipId)); }; openPhysicalAttachmentEditDialog = (attachment) => { @@ -201,19 +201,19 @@ class EquipmentDetail extends React.Component { physicalAttachmentEdited = () => { var equipId = this.props.match.params.equipmentId; - Api.getEquipment(equipId); + this.props.dispatch(Api.getEquipment(equipId)); }; - deletePhysicalAttachment = (attachmentId) => { - Api.deletePhysicalAttachment(attachmentId).then(() => { - let attachment = _.find( - this.props.equipment.equipmentAttachments, - (attachment) => attachment.id === attachmentId - ); - Log.equipmentAttachmentDeleted(this.props.equipment, attachment.typeName); - var equipId = this.props.match.params.equipmentId; - Api.getEquipment(equipId); - }); + deletePhysicalAttachment = async (attachmentId) => { + const dispatch = this.props.dispatch; + await dispatch(Api.deletePhysicalAttachment(attachmentId)); + let attachment = _.find( + this.props.equipment.equipmentAttachments, + (attachment) => attachment.id === attachmentId + ); + await dispatch(Log.equipmentAttachmentDeleted(this.props.equipment, attachment.typeName)); + const equipId = this.props.match.params.equipmentId; + dispatch(Api.getEquipment(equipId)); }; getLastVerifiedStyle = (equipment) => { @@ -247,6 +247,7 @@ class EquipmentDetail extends React.Component { render() { var equipment = this.props.equipment || {}; const { loadingNotes, loadingDocuments } = this.state; + const { dispatch } = this.props; var lastVerifiedStyle = this.getLastVerifiedStyle(equipment); @@ -601,8 +602,8 @@ class EquipmentDetail extends React.Component { show={this.state.showNotesDialog} id={this.props.match.params.equipmentId} notes={this.props.notes} - getNotes={Api.getEquipmentNotes} - saveNote={Api.addEquipmentNote} + getNotes={(equipmentId) => dispatch(Api.getEquipmentNotes(equipmentId))} + saveNote={(equipmentId, note) => dispatch(Api.addEquipmentNote(equipmentId, note))} onClose={this.closeNotesDialog} /> )} @@ -645,15 +646,15 @@ class EquipmentDetail extends React.Component { } } -function mapStateToProps(state) { - return { - equipment: activeEquipmentSelector(state), - notes: state.models.equipmentNotes, - attachments: state.models.equipmentAttachments, - documents: state.models.documents, - history: state.models.equipmentHistory, - ui: state.ui.equipmentPhysicalAttachments, - }; -} +const mapStateToProps = (state) => ({ + equipment: activeEquipmentSelector(state), + notes: state.models.equipmentNotes, + attachments: state.models.equipmentAttachments, + documents: state.models.documents, + history: state.models.equipmentHistory, + ui: state.ui.equipmentPhysicalAttachments, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(EquipmentDetail); +export default connect(mapStateToProps, mapDispatchToProps)(EquipmentDetail); diff --git a/client/src/js/views/HiringReport.jsx b/client/src/js/views/HiringReport.jsx index 6e8e3fd2b..7678e334f 100644 --- a/client/src/js/views/HiringReport.jsx +++ b/client/src/js/views/HiringReport.jsx @@ -8,7 +8,6 @@ import _ from 'lodash'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import PageHeader from '../components/ui/PageHeader.jsx'; import SearchBar from '../components/ui/SearchBar.jsx'; @@ -51,9 +50,9 @@ class HiringReport extends React.Component { } componentDidMount() { - Api.getProjectsCurrentFiscal(); - Api.getEquipmentHires(); - Api.getOwnersLiteHires(); + this.props.dispatch(Api.getProjectsCurrentFiscal()); + this.props.dispatch(Api.getEquipmentHires()); + this.props.dispatch(Api.getOwnersLiteHires()); // If this is the first load, then look for a default favourite if (_.isEmpty(this.props.search)) { @@ -87,7 +86,7 @@ class HiringReport extends React.Component { }; fetch = () => { - Api.searchHiringReport(this.buildSearchParams()); + this.props.dispatch(Api.searchHiringReport(this.buildSearchParams())); }; search = (e) => { @@ -104,17 +103,17 @@ class HiringReport extends React.Component { }; this.setState({ search: defaultSearchParameters }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_HIRING_RESPONSES_SEARCH, hiringResponses: this.state.search, }); - store.dispatch({ type: Action.CLEAR_HIRING_RESPONSES }); + this.props.dispatch({ type: Action.CLEAR_HIRING_RESPONSES }); }); }; updateSearchState = (state, callback) => { this.setState({ search: { ...this.state.search, ...state, ...{ loaded: true } } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_HIRING_RESPONSES_SEARCH, hiringResponses: this.state.search, }); @@ -126,7 +125,7 @@ class HiringReport extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_HIRING_RESPONSES_UI, hiringResponses: this.state.ui, }); @@ -372,17 +371,17 @@ class HiringReport extends React.Component { } } -function mapStateToProps(state) { - return { - projects: state.lookups.projectsCurrentFiscal, - localAreas: state.lookups.localAreas, - owners: state.lookups.owners.hires, - equipment: state.lookups.equipment.hires, - hiringResponses: state.models.hiringResponses, - favourites: state.models.favourites.hiringReport, - search: state.search.hiringResponses, - ui: state.ui.hiringResponses, - }; -} +const mapStateToProps = (state) => ({ + projects: state.lookups.projectsCurrentFiscal, + localAreas: state.lookups.localAreas, + owners: state.lookups.owners.hires, + equipment: state.lookups.equipment.hires, + hiringResponses: state.models.hiringResponses, + favourites: state.models.favourites.hiringReport, + search: state.search.hiringResponses, + ui: state.ui.hiringResponses, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(HiringReport); +export default connect(mapStateToProps, mapDispatchToProps)(HiringReport); diff --git a/client/src/js/views/Home.jsx b/client/src/js/views/Home.jsx index 8158f4a22..4b058c757 100644 --- a/client/src/js/views/Home.jsx +++ b/client/src/js/views/Home.jsx @@ -7,7 +7,6 @@ import _ from 'lodash'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import PageHeader from '../components/ui/PageHeader.jsx'; import SubHeader from '../components/ui/SubHeader.jsx'; @@ -24,20 +23,20 @@ class Home extends React.Component { } fetch = () => { - Api.getSearchSummaryCounts(); + this.props.dispatch(Api.getSearchSummaryCounts()); }; goToUnapprovedOwners = () => { var unapprovedStatus = Constant.OWNER_STATUS_CODE_PENDING; // update search parameters - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_OWNERS_SEARCH, owners: { statusCode: unapprovedStatus }, }); // perform search - Api.searchOwners({ status: unapprovedStatus }); + this.props.dispatch(Api.searchOwners({ status: unapprovedStatus })); // navigate to search page this.props.history.push({ pathname: Constant.OWNERS_PATHNAME }); @@ -47,13 +46,13 @@ class Home extends React.Component { var unapprovedStatus = Constant.EQUIPMENT_STATUS_CODE_PENDING; // update search parameters - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_EQUIPMENT_LIST_SEARCH, equipmentList: { statusCode: Constant.EQUIPMENT_STATUS_CODE_PENDING }, }); // perform search - Api.searchEquipmentList({ status: unapprovedStatus }); + this.props.dispatch(Api.searchEquipmentList({ status: unapprovedStatus })); // navigate to search page this.props.history.push({ pathname: Constant.EQUIPMENT_PATHNAME }); @@ -61,7 +60,7 @@ class Home extends React.Component { goToHiredEquipment = () => { // update search parameters - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_EQUIPMENT_LIST_SEARCH, equipmentList: { statusCode: Constant.EQUIPMENT_STATUS_CODE_APPROVED, @@ -70,10 +69,10 @@ class Home extends React.Component { }); // perform search - Api.searchEquipmentList({ + this.props.dispatch(Api.searchEquipmentList({ status: Constant.EQUIPMENT_STATUS_CODE_APPROVED, hired: true, - }); + })); // navigate to search page this.props.history.push({ pathname: Constant.EQUIPMENT_PATHNAME }); @@ -81,7 +80,7 @@ class Home extends React.Component { goToBlockedRotationLists = () => { // update search parameters - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_RENTAL_REQUESTS_SEARCH, rentalRequests: { statusCode: Constant.RENTAL_REQUEST_STATUS_CODE_IN_PROGRESS, @@ -89,9 +88,9 @@ class Home extends React.Component { }); // perform search - Api.searchRentalRequests({ + this.props.dispatch(Api.searchRentalRequests({ status: Constant.RENTAL_REQUEST_STATUS_CODE_IN_PROGRESS, - }); + })); // navigate to search page this.props.history.push({ pathname: Constant.RENTAL_REQUESTS_PATHNAME }); @@ -131,11 +130,11 @@ class Home extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - searchSummaryCounts: state.lookups.searchSummaryCounts, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + searchSummaryCounts: state.lookups.searchSummaryCounts, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(Home); +export default connect(mapStateToProps, mapDispatchToProps)(Home); diff --git a/client/src/js/views/Main.jsx b/client/src/js/views/Main.jsx index 5e8f2df81..213ad164b 100644 --- a/client/src/js/views/Main.jsx +++ b/client/src/js/views/Main.jsx @@ -52,26 +52,26 @@ class Main extends React.Component { // redirects regular users to rollover page if rollover in progress redirectIfRolloverActive(path) { - var onBusinessPage = path.indexOf(Constant.BUSINESS_PORTAL_PATHNAME) === 0; - var onRolloverPage = path === Constant.ROLLOVER_PATHNAME; + const onBusinessPage = path.indexOf(Constant.BUSINESS_PORTAL_PATHNAME) === 0; + const onRolloverPage = path === Constant.ROLLOVER_PATHNAME; if (onBusinessPage || onRolloverPage) { return; } - var { user } = this.props; + const { user, dispatch } = this.props; if (!user.district) { return; } const districtId = user.district.id; - Api.getRolloverStatus(districtId).then(() => { + dispatch(Api.getRolloverStatus(districtId)).then(() => { const status = this.props.lookups.rolloverStatus; if (status.rolloverActive) { this.props.history.push(Constant.ROLLOVER_PATHNAME); } else if (status.rolloverComplete) { // refresh fiscal years - Api.getFiscalYears(districtId); + dispatch(Api.getFiscalYears(districtId)); } }); } @@ -128,17 +128,16 @@ class Main extends React.Component { } } -function mapStateToProps(state) { - return { - showSessionTimeoutDialog: state.ui.showSessionTimeoutDialog, - showErrorDialog: state.ui.showErrorDialog, - user: state.user, - lookups: state.lookups, - }; -} - -function mapDispatchToProps(dispatch) { - return bindActionCreators({ unhandledApiError, closeSessionTimeoutDialog }, dispatch); -} +const mapStateToProps = (state) => ({ + showSessionTimeoutDialog: state.ui.showSessionTimeoutDialog, + showErrorDialog: state.ui.showErrorDialog, + user: state.user, + lookups: state.lookups, +}); + +const mapDispatchToProps = (dispatch) => ({ + dispatch, + ...bindActionCreators({ unhandledApiError, closeSessionTimeoutDialog }, dispatch) +}); export default connect(mapStateToProps, mapDispatchToProps)(withRouter(Main)); diff --git a/client/src/js/views/OvertimeRates.jsx b/client/src/js/views/OvertimeRates.jsx index 72fd3ec17..b38775140 100644 --- a/client/src/js/views/OvertimeRates.jsx +++ b/client/src/js/views/OvertimeRates.jsx @@ -34,7 +34,7 @@ class OvertimeRates extends React.Component { } fetch = () => { - Api.getOvertimeRateTypes(); + this.props.dispatch(Api.getOvertimeRateTypes()); }; editRate = (overtimeRateType) => { @@ -118,11 +118,11 @@ class OvertimeRates extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - overtimeRateTypes: state.lookups.overtimeRateTypes, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + overtimeRateTypes: state.lookups.overtimeRateTypes, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(OvertimeRates); +export default connect(mapStateToProps, mapDispatchToProps)(OvertimeRates); diff --git a/client/src/js/views/Owners.jsx b/client/src/js/views/Owners.jsx index f7eb0f53c..bc8b59d09 100644 --- a/client/src/js/views/Owners.jsx +++ b/client/src/js/views/Owners.jsx @@ -9,7 +9,6 @@ import OwnersAddDialog from './dialogs/OwnersAddDialog.jsx'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import AddButtonContainer from '../components/ui/AddButtonContainer.jsx'; import PageHeader from '../components/ui/PageHeader.jsx'; @@ -91,7 +90,7 @@ class Owners extends React.Component { } fetch = () => { - Api.searchOwners(this.buildSearchParams()); + this.props.dispatch(Api.searchOwners(this.buildSearchParams())); }; search = () => { @@ -107,14 +106,14 @@ class Owners extends React.Component { }; this.setState({ search: defaultSearchParameters }, () => { - store.dispatch({ type: Action.UPDATE_OWNERS_SEARCH, owners: this.state.search }); - store.dispatch({ type: Action.CLEAR_OWNERS }); + this.props.dispatch({ type: Action.UPDATE_OWNERS_SEARCH, owners: this.state.search }); + this.props.dispatch({ type: Action.CLEAR_OWNERS }); }); }; updateSearchState = (state, callback) => { this.setState({ search: { ...this.state.search, ...state, ...{ loaded: true } } }, () => { - store.dispatch({ type: Action.UPDATE_OWNERS_SEARCH, owners: this.state.search }); + this.props.dispatch({ type: Action.UPDATE_OWNERS_SEARCH, owners: this.state.search }); if (callback) { callback(); } @@ -123,7 +122,7 @@ class Owners extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_OWNERS_UI, owners: this.state.ui }); + this.props.dispatch({ type: Action.UPDATE_OWNERS_UI, owners: this.state.ui }); if (callback) { callback(); } @@ -316,15 +315,15 @@ class Owners extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - ownerList: state.models.owners, - localAreas: state.lookups.localAreas, - favourites: state.models.favourites.owner, - search: state.search.owners, - ui: state.ui.owners, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + ownerList: state.models.owners, + localAreas: state.lookups.localAreas, + favourites: state.models.favourites.owner, + search: state.search.owners, + ui: state.ui.owners, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(Owners); +export default connect(mapStateToProps, mapDispatchToProps)(Owners); diff --git a/client/src/js/views/OwnersDetail.jsx b/client/src/js/views/OwnersDetail.jsx index 8c52daa86..d947155be 100644 --- a/client/src/js/views/OwnersDetail.jsx +++ b/client/src/js/views/OwnersDetail.jsx @@ -20,7 +20,6 @@ import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; import * as Log from '../history'; -import store from '../store'; import CheckboxControl from '../components/CheckboxControl.jsx'; import ColDisplay from '../components/ColDisplay.jsx'; @@ -104,29 +103,31 @@ class OwnersDetail extends React.Component { } componentDidMount() { - store.dispatch({ + this.props.dispatch({ type: Action.SET_ACTIVE_OWNER_ID_UI, ownerId: this.props.match.params.ownerId, }); const ownerId = this.props.match.params.ownerId; /* Documents need be fetched every time as they are not project specific in the store ATM */ - Api.getOwnerDocuments(ownerId).then(() => this.setState({ loadingDocuments: false })); + this.props.dispatch(Api.getOwnerDocuments(ownerId)) + .then(() => this.setState({ loadingDocuments: false })); // Re-fetch project and notes every time - Promise.all([this.fetch(), Api.getOwnerNotes(ownerId)]).then(() => { + Promise.all([this.fetch(), this.props.dispatch(Api.getOwnerNotes(ownerId))]).then(() => { this.setState({ loading: false }); }); } fetch = () => { this.setState({ reloading: true }); - return Api.getOwner(this.props.match.params.ownerId).then(() => this.setState({ reloading: false })); + return this.props.dispatch(Api.getOwner(this.props.match.params.ownerId)) + .then(() => this.setState({ reloading: false })); }; updateContactsUIState = (state, callback) => { this.setState({ uiContacts: { ...this.state.uiContacts, ...state } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_OWNER_CONTACTS_UI, ownerContacts: this.state.uiContacts, }); @@ -138,7 +139,7 @@ class OwnersDetail extends React.Component { updateEquipmentUIState = (state, callback) => { this.setState({ uiEquipment: { ...this.state.uiEquipment, ...state } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_OWNER_EQUIPMENT_UI, ownerEquipment: this.state.uiEquipment, }); @@ -168,7 +169,7 @@ class OwnersDetail extends React.Component { onStatusChanged = () => { this.closeChangeStatusDialog(); - Api.getOwnerNotes(this.props.owner.id); + this.props.dispatch(Api.getOwnerNotes(this.props.owner.id)); }; showDocuments = () => { @@ -188,7 +189,7 @@ class OwnersDetail extends React.Component { }; ownerSaved = () => { - Log.ownerModified(this.props.owner); + this.props.dispatch(Log.ownerModified(this.props.owner)); }; openContactDialog = (contactId) => { @@ -214,8 +215,9 @@ class OwnersDetail extends React.Component { }; deleteContact = (contact) => { - Api.deleteContact(contact).then(() => { - Log.ownerContactDeleted(this.props.owner, contact).then(() => { + const dispatch = this.props.dispatch; + dispatch(Api.deleteContact(contact)).then(() => { + dispatch(Log.ownerContactDeleted(this.props.owner, contact)).then(() => { // In addition to refreshing the contacts, we need to update the owner // to get primary contact info and history. this.fetch(); @@ -224,10 +226,10 @@ class OwnersDetail extends React.Component { }; contactSaved = (contact) => { - var isNew = !contact.id; - var log = isNew ? Log.ownerContactAdded : Log.ownerContactUpdated; + const isNew = !contact.id; + const log = isNew ? Log.ownerContactAdded : Log.ownerContactUpdated; - log(this.props.owner, contact).then(() => { + this.props.dispatch(log(this.props.owner, contact)).then(() => { // In addition to refreshing the contacts, we need to update the owner // to get primary contact info and history. this.fetch(); @@ -244,22 +246,24 @@ class OwnersDetail extends React.Component { this.setState({ showEquipmentDialog: false }); }; - equipmentSaved = (equipment) => { + equipmentSaved = async (equipment) => { + const { dispatch, history, owner } = this.props; this.closeEquipmentDialog(); - Log.ownerEquipmentAdded(this.props.owner, equipment); - Log.equipmentAdded(equipment); + await dispatch(Log.ownerEquipmentAdded(owner, equipment)); + await dispatch(Log.equipmentAdded(equipment)); // Open it up - this.props.history.push(`${Constant.EQUIPMENT_PATHNAME}/${equipment.id}`, { - returnUrl: `${Constant.OWNERS_PATHNAME}/${this.props.owner.id}`, + history.push(`${Constant.EQUIPMENT_PATHNAME}/${equipment.id}`, { + returnUrl: `${Constant.OWNERS_PATHNAME}/${owner.id}`, }); }; - equipmentVerifyAll = () => { - var now = today(); - var owner = this.props.owner; + equipmentVerifyAll = async () => { + const now = today(); + let owner = this.props.owner; + const dispatch = this.props.dispatch; // Update the last verified date on all pieces of equipment - var equipmentList = _.map(owner.equipmentList, (equipment) => { + let equipmentList = _.map(owner.equipmentList, (equipment) => { return { ...equipment, lastVerifiedDate: toZuluTime(now), @@ -267,27 +271,27 @@ class OwnersDetail extends React.Component { }; }); - Api.updateOwnerEquipment(owner, equipmentList).then(() => { - //thought about using response data to log, however the server response doesn't contain equipment.History entity which breaks logging - equipmentList.forEach((updatedEquipment) => { - Log.ownerEquipmentVerified(this.props.owner, updatedEquipment); - }); - this.fetch(); + await dispatch(Api.updateOwnerEquipment(owner, equipmentList)); + //thought about using response data to log, however the server response doesn't contain equipment.History entity which breaks logging + owner = this.props.owner; + equipmentList.forEach(async (updatedEquipment) => { + await dispatch(Log.ownerEquipmentVerified(owner, updatedEquipment)); }); + this.fetch(); }; - equipmentVerify = (equipment) => { - const updatedEquipment = { + equipmentVerify = async (equipment) => { + const { dispatch, owner } = this.props; + let updatedEquipment = { ...equipment, lastVerifiedDate: toZuluTime(today()), - owner: { id: this.props.owner.id }, + owner: { id: owner.id }, }; - Log.ownerEquipmentVerified(this.props.owner, updatedEquipment); + await dispatch(Log.ownerEquipmentVerified(owner, updatedEquipment)); - Api.updateEquipment(updatedEquipment).then(() => { - this.fetch(); - }); + await dispatch(Api.updateEquipment(updatedEquipment)); + this.fetch(); }; openPolicyDialog = () => { @@ -299,7 +303,7 @@ class OwnersDetail extends React.Component { }; policySaved = () => { - Log.ownerModifiedPolicy(this.props.owner); + this.props.dispatch(Log.ownerModifiedPolicy(this.props.owner)); }; openPolicyDocumentsDialog = () => { @@ -330,6 +334,7 @@ class OwnersDetail extends React.Component { render() { const { loading, loadingDocuments } = this.state; var owner = this.props.owner || {}; + const dispatch = this.props.dispatch; var isApproved = owner.status === Constant.OWNER_STATUS_CODE_APPROVED; var restrictEquipmentAddTooltip = 'Equipment can only be added to an approved owner.'; @@ -771,8 +776,8 @@ class OwnersDetail extends React.Component { show={this.state.showNotesDialog} id={this.props.match.params.ownerId} notes={owner.notes} - getNotes={Api.getOwnerNotes} - saveNote={Api.addOwnerNote} + getNotes={(ownerId) => dispatch(Api.getOwnerNotes(ownerId))} + saveNote={(ownerId, note) => dispatch(Api.addOwnerNote(ownerId, note))} onClose={this.closeNotesDialog} /> )} @@ -812,7 +817,7 @@ class OwnersDetail extends React.Component { show={this.state.showContactDialog} contact={this.state.contact} parent={owner} - saveContact={Api.saveOwnerContact} + saveContact={(owner, contact) => dispatch(Api.saveOwnerContact(owner, contact))} defaultPrimary={owner.contacts.length === 0} onSave={this.contactSaved} onClose={this.closeContactDialog} @@ -833,13 +838,13 @@ class OwnersDetail extends React.Component { } } -function mapStateToProps(state) { - return { - owner: activeOwnerSelector(state), - documents: state.models.documents, - uiContacts: state.ui.ownerContacts, - uiEquipment: state.ui.ownerEquipment, - }; -} +const mapStateToProps = (state) => ({ + owner: activeOwnerSelector(state), + documents: state.models.documents, + uiContacts: state.ui.ownerContacts, + uiEquipment: state.ui.ownerEquipment, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(OwnersDetail); +export default connect(mapStateToProps, mapDispatchToProps)(OwnersDetail); diff --git a/client/src/js/views/Projects.jsx b/client/src/js/views/Projects.jsx index 2792a88ce..beb6bde6f 100644 --- a/client/src/js/views/Projects.jsx +++ b/client/src/js/views/Projects.jsx @@ -10,7 +10,6 @@ import ProjectsAddDialog from './dialogs/ProjectsAddDialog.jsx'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import AddButtonContainer from '../components/ui/AddButtonContainer.jsx'; import PageHeader from '../components/ui/PageHeader.jsx'; @@ -86,7 +85,7 @@ class Projects extends React.Component { } fetch = () => { - Api.searchProjects(this.buildSearchParams()); + this.props.dispatch(Api.searchProjects(this.buildSearchParams())); }; search = (e) => { @@ -95,7 +94,7 @@ class Projects extends React.Component { }; clearSearch = () => { - var defaultSearchParameters = { + const defaultSearchParameters = { statusCode: Constant.PROJECT_STATUS_CODE_ACTIVE, projectName: '', projectNumber: '', @@ -103,14 +102,14 @@ class Projects extends React.Component { }; this.setState({ search: defaultSearchParameters }, () => { - store.dispatch({ type: Action.UPDATE_PROJECTS_SEARCH, projects: this.state.search }); - store.dispatch({ type: Action.CLEAR_PROJECTS }); + this.props.dispatch({ type: Action.UPDATE_PROJECTS_SEARCH, projects: this.state.search }); + this.props.dispatch({ type: Action.CLEAR_PROJECTS }); }); }; updateSearchState = (state, callback) => { this.setState({ search: { ...this.state.search, ...state, ...{ loaded: true } } }, () => { - store.dispatch({ type: Action.UPDATE_PROJECTS_SEARCH, projects: this.state.search }); + this.props.dispatch({ type: Action.UPDATE_PROJECTS_SEARCH, projects: this.state.search }); if (callback) { callback(); } @@ -119,7 +118,7 @@ class Projects extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_PROJECTS_UI, projects: this.state.ui }); + this.props.dispatch({ type: Action.UPDATE_PROJECTS_UI, projects: this.state.ui }); if (callback) { callback(); } @@ -309,14 +308,14 @@ class Projects extends React.Component { } } -function mapStateToProps(state) { - return { - fiscalYears: state.lookups.fiscalYears, - projects: state.models.projects, - favourites: state.models.favourites.project, - search: state.search.projects, - ui: state.ui.projects, - }; -} +const mapStateToProps = (state) => ({ + fiscalYears: state.lookups.fiscalYears, + projects: state.models.projects, + favourites: state.models.favourites.project, + search: state.search.projects, + ui: state.ui.projects, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(Projects); +export default connect(mapStateToProps, mapDispatchToProps)(Projects); diff --git a/client/src/js/views/ProjectsDetail.jsx b/client/src/js/views/ProjectsDetail.jsx index 1c2d13fd8..c4a155cdb 100644 --- a/client/src/js/views/ProjectsDetail.jsx +++ b/client/src/js/views/ProjectsDetail.jsx @@ -18,7 +18,6 @@ import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; import * as Log from '../history'; -import store from '../store'; import CheckboxControl from '../components/CheckboxControl.jsx'; import ColDisplay from '../components/ColDisplay.jsx'; @@ -88,7 +87,8 @@ class ProjectsDetail extends React.Component { componentDidMount() { //dispatch Set_ACTIVE_PROJECT_ID_UI needed for activeProjectSelector(state) to work. Solution uses redux state to pass argument values to another selector. //https://github.com/reduxjs/reselect#q-how-do-i-create-a-selector-that-takes-an-argument - store.dispatch({ + const dispatch = this.props.dispatch; + dispatch({ type: Action.SET_ACTIVE_PROJECT_ID_UI, projectId: this.props.match.params.projectId, }); @@ -97,7 +97,8 @@ class ProjectsDetail extends React.Component { const projectId = this.props.match.params.projectId; /* Documents need be fetched every time as they are not project specific in the store ATM */ - Api.getProjectDocuments(projectId).then(() => this.setState({ loadingDocuments: false })); + dispatch(Api.getProjectDocuments(projectId)) + .then(() => this.setState({ loadingDocuments: false })); // Only show loading spinner if there is no existing project in the store if (project) { @@ -105,14 +106,15 @@ class ProjectsDetail extends React.Component { } // Re-fetch project and notes every time - Promise.all([this.fetch(), Api.getProjectNotes(projectId)]).then(() => { + Promise.all([this.fetch(), dispatch(Api.getProjectNotes(projectId))]).then(() => { this.setState({ loading: false }); }); } fetch = () => { this.setState({ reloading: true }); - return Api.getProject(this.props.match.params.projectId).then(() => this.setState({ reloading: false })); + return this.props.dispatch(Api.getProject(this.props.match.params.projectId)) + .then(() => this.setState({ reloading: false })); }; updateState = (state, callback) => { @@ -121,7 +123,7 @@ class ProjectsDetail extends React.Component { updateContactsUIState = (state, callback) => { this.setState({ uiContacts: { ...this.state.uiContacts, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_PROJECT_CONTACTS_UI, projectContacts: this.state.uiContacts }); + this.props.dispatch({ type: Action.UPDATE_PROJECT_CONTACTS_UI, projectContacts: this.state.uiContacts }); if (callback) { callback(); } @@ -177,18 +179,19 @@ class ProjectsDetail extends React.Component { }; deleteContact = (contact) => { - Api.deleteContact(contact).then(() => { - Log.projectContactDeleted(this.props.project, contact).then(() => { + const dispatch = this.props.dispatch; + dispatch(Api.deleteContact(contact)).then(() => { + dispatch(Log.projectContactDeleted(this.props.project, contact)).then(() => { this.fetch(); }); }); }; contactSaved = (contact) => { - var isNew = !contact.id; - var log = isNew ? Log.projectContactAdded : Log.projectContactUpdated; + const isNew = !contact.id; + const log = isNew ? Log.projectContactAdded : Log.projectContactUpdated; - log(this.props.project, contact).then(() => { + this.props.dispatch(log(this.props.project, contact)).then(() => { // In addition to refreshing the contacts, we need to update the owner // to get primary contact info and history. this.fetch(); @@ -205,19 +208,17 @@ class ProjectsDetail extends React.Component { this.setState({ showAddRequestDialog: false }); }; - newRentalAdded = (rentalRequest) => { - this.fetch(); - - Log.projectRentalRequestAdded(this.props.project, rentalRequest); - + newRentalAdded = async (rentalRequest) => { + await this.fetch(); + await this.props.dispatch(Log.projectRentalRequestAdded(this.props.project, rentalRequest)); this.props.history.push(`${Constant.RENTAL_REQUESTS_PATHNAME}/${rentalRequest.id}`); }; - confirmEndHire = (item) => { - Api.releaseRentalAgreement(item.id).then(() => { - Api.getProject(this.props.match.params.projectId); - Log.projectEquipmentReleased(this.props.project, item.equipment); - }); + confirmEndHire = async (item) => { + const dispatch = this.props.dispatch; + await dispatch(Api.releaseRentalAgreement(item.id)); + await dispatch(Api.getProject(this.props.match.params.projectId)); + dispatch(Log.projectEquipmentReleased(this.props.project, item.equipment)); }; openTimeEntryDialog = (rentalAgreement) => { @@ -233,10 +234,9 @@ class ProjectsDetail extends React.Component { this.setState({ showTimeEntryDialog: false }); }; - cancelRequest = (request) => { - Api.cancelRentalRequest(request.id).then(() => { - this.fetch(); - }); + cancelRequest = async (request) => { + await this.props.dispatch(Api.cancelRentalRequest(request.id)); + this.fetch(); }; renderRentalRequestListItem = (item) => { @@ -324,22 +324,24 @@ class ProjectsDetail extends React.Component { return _.pull([Constant.PROJECT_STATUS_CODE_ACTIVE, Constant.PROJECT_STATUS_CODE_COMPLETED], project.status); }; - updateStatusState = (state) => { - if (state !== this.props.project.status) { - const project = { - ...this.props.project, + updateStatusState = async (state) => { + const { dispatch, project } = this.props; + if (state !== project.status) { + const updatedProject = { + ...project, status: state, }; - store.dispatch({ type: Action.UPDATE_PROJECT, project }); - Log.projectModifiedStatus(project); - Api.updateProject(project); + await dispatch({ type: Action.UPDATE_PROJECT, updatedProject }); + await dispatch(Log.projectModifiedStatus(updatedProject)); + await dispatch(Api.updateProject(updatedProject)); } }; render() { const { loading, loadingDocuments } = this.state; var project = this.props.project || {}; + const dispatch = this.props.dispatch; // As per business requirements: // "Lists the records - requests then rental agreements, within the groups, list in largest-to-smallest ID order (aka reverse chronological create)." @@ -651,8 +653,8 @@ class ProjectsDetail extends React.Component { dispatch(Api.getProjectNotes(projectId))} + saveNote={(projectId, note) => dispatch(Api.addProjectNote(projectId, note))} onClose={this.closeNotesDialog} notes={project.notes} /> @@ -684,7 +686,7 @@ class ProjectsDetail extends React.Component { {this.state.showContactDialog && ( dispatch(Api.saveProjectContact(project, contact))} contact={this.state.contact} parent={project} onSave={this.contactSaved} @@ -696,12 +698,12 @@ class ProjectsDetail extends React.Component { } } -function mapStateToProps(state) { - return { - project: activeProjectSelector(state), - documents: state.models.documents, - uiContacts: state.ui.projectContacts, - }; -} +const mapStateToProps = (state) => ({ + project: activeProjectSelector(state), + documents: state.models.documents, + uiContacts: state.ui.projectContacts, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(ProjectsDetail); +export default connect(mapStateToProps, mapDispatchToProps)(ProjectsDetail); diff --git a/client/src/js/views/RentalAgreementsDetail.jsx b/client/src/js/views/RentalAgreementsDetail.jsx index 06284964a..1506ccb73 100644 --- a/client/src/js/views/RentalAgreementsDetail.jsx +++ b/client/src/js/views/RentalAgreementsDetail.jsx @@ -17,7 +17,6 @@ import CloneDialog from './dialogs/CloneDialog.jsx'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import ColDisplay from '../components/ColDisplay.jsx'; import DeleteButton from '../components/DeleteButton.jsx'; @@ -61,7 +60,7 @@ class RentalAgreementsDetail extends React.Component { } componentDidMount() { - store.dispatch({ + this.props.dispatch({ type: Action.SET_ACTIVE_RENTAL_AGREEMENT_ID_UI, rentalAgreementId: this.props.match.params.rentalAgreementId, }); @@ -75,7 +74,7 @@ class RentalAgreementsDetail extends React.Component { } fetch = () => { - return Api.getRentalAgreement(this.props.match.params.rentalAgreementId); + return this.props.dispatch(Api.getRentalAgreement(this.props.match.params.rentalAgreementId)); }; updateState = (state, callback) => { @@ -119,7 +118,7 @@ class RentalAgreementsDetail extends React.Component { }; deleteRentalRate = (rentalRate) => { - Api.deleteRentalRate(rentalRate).then(() => { + this.props.dispatch(Api.deleteRentalRate(rentalRate)).then(() => { // In addition to refreshing the rental rates, we need to update the rental agreement to get // possibly new info. this.fetch(); @@ -144,12 +143,12 @@ class RentalAgreementsDetail extends React.Component { }); }; - deleteCondition = (rentalCondition) => { - Api.deleteRentalCondition(rentalCondition).then(() => { - // In addition to refreshing the rental condition, we need to update the rental agreement to - // get possibly new info. - this.fetch(); - }); + deleteCondition = async (rentalCondition) => { + await this.props.dispatch(Api.deleteRentalCondition(rentalCondition)); + + // In addition to refreshing the rental condition, we need to update the rental agreement to + // get possibly new info. + this.fetch(); }; openOvertimeNotesDialog = () => { @@ -160,13 +159,12 @@ class RentalAgreementsDetail extends React.Component { this.setState({ showOvertimeNotesDialog: false }); }; - generateRentalAgreementDocument = () => { - let request = Api.generateRentalAgreementDocument(this.props.match.params.rentalAgreementId); - let fname = `rental-agreement-${formatDateTimeUTCToLocal(new Date(), Constant.DATE_TIME_FILENAME)}`; + generateRentalAgreementDocument = async () => { + const dispatch = this.props.dispatch; + const fname = `rental-agreement-${formatDateTimeUTCToLocal(new Date(), Constant.DATE_TIME_FILENAME)}`; - request.getBlob().then((res) => { - saveAs(res.response, fname); - }); + const res = await dispatch(Api.generateRentalAgreementDocument(this.props.match.params.rentalAgreementId)); + saveAs(res.response, fname); }; openCloneDialog = () => { @@ -718,10 +716,10 @@ class RentalAgreementsDetail extends React.Component { } } -function mapStateToProps(state) { - return { - rentalAgreement: activeRentalAgreementSelector(state), - }; -} +const mapStateToProps = (state) => ({ + rentalAgreement: activeRentalAgreementSelector(state), +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(RentalAgreementsDetail); +export default connect(mapStateToProps, mapDispatchToProps)(RentalAgreementsDetail); diff --git a/client/src/js/views/RentalRequests.jsx b/client/src/js/views/RentalRequests.jsx index 5f5e273ff..9bb7cb51c 100644 --- a/client/src/js/views/RentalRequests.jsx +++ b/client/src/js/views/RentalRequests.jsx @@ -13,7 +13,6 @@ import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; import * as Log from '../history'; -import store from '../store'; import AddButtonContainer from '../components/ui/AddButtonContainer.jsx'; import PageHeader from '../components/ui/PageHeader.jsx'; @@ -159,7 +158,7 @@ class RentalRequests extends React.Component { } fetch = () => { - Api.searchRentalRequests(this.buildSearchParams()); + this.props.dispatch(Api.searchRentalRequests(this.buildSearchParams())); }; search = (e) => { @@ -168,7 +167,8 @@ class RentalRequests extends React.Component { }; clearSearch = () => { - var defaultSearchParameters = { + const dispatch = this.props.dispatch; + const defaultSearchParameters = { selectedLocalAreasIds: [], projectName: '', status: Constant.RENTAL_REQUEST_STATUS_CODE_IN_PROGRESS, @@ -176,14 +176,15 @@ class RentalRequests extends React.Component { }; this.setState({ search: defaultSearchParameters }, () => { - store.dispatch({ type: Action.UPDATE_RENTAL_REQUESTS_SEARCH, rentalRequests: this.state.search }); - store.dispatch({ type: Action.CLEAR_RENTAL_REQUESTS }); + dispatch({ type: Action.UPDATE_RENTAL_REQUESTS_SEARCH, rentalRequests: this.state.search }); + dispatch({ type: Action.CLEAR_RENTAL_REQUESTS }); }); }; updateSearchState = (state, callback) => { + const dispatch = this.props.dispatch; this.setState({ search: { ...this.state.search, ...state, ...{ loaded: true } } }, () => { - store.dispatch({ type: Action.UPDATE_RENTAL_REQUESTS_SEARCH, rentalRequests: this.state.search }); + dispatch({ type: Action.UPDATE_RENTAL_REQUESTS_SEARCH, rentalRequests: this.state.search }); if (callback) { callback(); } @@ -191,8 +192,9 @@ class RentalRequests extends React.Component { }; updateUIState = (state, callback) => { + const dispatch = this.props.dispatch; this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_RENTAL_REQUESTS_UI, rentalRequests: this.state.ui }); + dispatch({ type: Action.UPDATE_RENTAL_REQUESTS_UI, rentalRequests: this.state.ui }); if (callback) { callback(); } @@ -203,10 +205,9 @@ class RentalRequests extends React.Component { this.updateSearchState(JSON.parse(favourite.value), this.fetch); }; - deleteRequest = (request) => { - Api.cancelRentalRequest(request.id).then(() => { - this.fetch(); - }); + deleteRequest = async (request) => { + await this.props.dispatch(Api.cancelRentalRequest(request.id)); + this.fetch(); }; openAddDialog = (viewOnly) => { @@ -217,9 +218,8 @@ class RentalRequests extends React.Component { this.setState({ showAddDialog: false }); }; - newRentalAdded = (rentalRequest) => { - Log.rentalRequestAdded(rentalRequest); - + newRentalAdded = async (rentalRequest) => { + await this.props.dispatch(Log.rentalRequestAdded(rentalRequest)); this.props.history.push(`${Constant.RENTAL_REQUESTS_PATHNAME}/${rentalRequest.id}`); }; @@ -484,15 +484,15 @@ class RentalRequests extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - rentalRequests: state.models.rentalRequests, - localAreas: state.lookups.localAreas, - favourites: state.models.favourites.rentalRequests, - search: state.search.rentalRequests, - ui: state.ui.rentalRequests, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + rentalRequests: state.models.rentalRequests, + localAreas: state.lookups.localAreas, + favourites: state.models.favourites.rentalRequests, + search: state.search.rentalRequests, + ui: state.ui.rentalRequests, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(RentalRequests); +export default connect(mapStateToProps, mapDispatchToProps)(RentalRequests); diff --git a/client/src/js/views/RentalRequestsDetail.jsx b/client/src/js/views/RentalRequestsDetail.jsx index b31f1d540..08012d4a0 100644 --- a/client/src/js/views/RentalRequestsDetail.jsx +++ b/client/src/js/views/RentalRequestsDetail.jsx @@ -17,7 +17,6 @@ import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; import * as Log from '../history'; -import store from '../store'; import CheckboxControl from '../components/CheckboxControl.jsx'; import ColDisplay from '../components/ColDisplay.jsx'; @@ -78,7 +77,8 @@ class RentalRequestsDetail extends React.Component { } componentDidMount() { - store.dispatch({ + const dispatch = this.props.dispatch; + dispatch({ type: Action.SET_ACTIVE_RENTAL_REQUEST_ID_UI, rentalRequestId: this.props.match.params.rentalRequestId, }); @@ -86,23 +86,23 @@ class RentalRequestsDetail extends React.Component { const rentalRequestId = this.props.match.params.rentalRequestId; /* Documents need be fetched every time as they are not rentalRequest specific in the store ATM */ - Api.getRentalRequestDocuments(rentalRequestId).then(() => this.setState({ loadingDocuments: false })); + dispatch(Api.getRentalRequestDocuments(rentalRequestId)) + .then(() => this.setState({ loadingDocuments: false })); // Re-fetch rental request, rotationlist, and notes every time Promise.all([ this.fetch(), - Api.getRentalRequestNotes(rentalRequestId), - Api.getRentalRequestRotationList(rentalRequestId), + dispatch(Api.getRentalRequestNotes(rentalRequestId)), + dispatch(Api.getRentalRequestRotationList(rentalRequestId)), ]).then(() => { this.setState({ loading: false }); }); } - fetch = () => { + fetch = async () => { this.setState({ reloading: true }); - return Api.getRentalRequest(this.props.match.params.rentalRequestId).then(() => - this.setState({ reloading: false }) - ); + await this.props.dispatch(Api.getRentalRequest(this.props.match.params.rentalRequestId)); + this.setState({ reloading: false }); }; updateState = (state, callback) => { @@ -110,8 +110,9 @@ class RentalRequestsDetail extends React.Component { }; updateContactsUIState = (state, callback) => { + const dispatch = this.props.dispatch; this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ + dispatch({ type: Action.UPDATE_PROJECT_CONTACTS_UI, projectContacts: this.state.ui, }); @@ -148,7 +149,10 @@ class RentalRequestsDetail extends React.Component { }; rentalRequestSaved = () => { - Promise.all([this.fetch(), Api.getRentalRequestRotationList(this.props.match.params.rentalRequestId)]); + Promise.all([ + this.fetch(), + this.props.dispatch(Api.getRentalRequestRotationList(this.props.match.params.rentalRequestId)) + ]); }; openHireOfferDialog = (hireOffer, showAllResponseFields) => { @@ -163,12 +167,12 @@ class RentalRequestsDetail extends React.Component { this.setState({ showHireOfferDialog: false }); }; - hireOfferSaved = (hireOffer) => { - Log.rentalRequestEquipmentHired(this.props.rentalRequest, hireOffer.equipment, hireOffer.offerResponse); + hireOfferSaved = async (hireOffer) => { + await this.props.dispatch(Log.rentalRequestEquipmentHired(this.props.rentalRequest, hireOffer.equipment, hireOffer.offerResponse)); this.closeHireOfferDialog(); - var rotationListItem = _.find(this.props.rentalRequest.rotationList, (i) => i.id === hireOffer.id); + let rotationListItem = _.find(this.props.rentalRequest.rotationList, (i) => i.id === hireOffer.id); if (rotationListItem && rotationListItem.rentalAgreementId && !hireOffer.rentalAgreementId) { // navigate to rental agreement if it was newly generated this.props.history.push(`${Constant.RENTAL_AGREEMENTS_PATHNAME}/${rotationListItem.rentalAgreementId}`); @@ -178,15 +182,14 @@ class RentalRequestsDetail extends React.Component { } }; - printSeniorityList = () => { - let filename = 'SeniorityList-' + formatDateTimeUTCToLocal(new Date(), Constant.DATE_TIME_FILENAME) + '.docx'; - Api.rentalRequestSeniorityList(this.props.rentalRequest.id) - .then((res) => { - saveAs(res, filename); - }) - .catch((error) => { - console.log(error); - }); + printSeniorityList = async () => { + const filename = 'SeniorityList-' + formatDateTimeUTCToLocal(new Date(), Constant.DATE_TIME_FILENAME) + '.docx'; + try { + const res = await this.props.dispatch(Api.rentalRequestSeniorityList(this.props.rentalRequest.id)); + saveAs(res, filename); + } catch(error) { + console.log(error); + } }; addRequest = () => {}; @@ -207,10 +210,11 @@ class RentalRequestsDetail extends React.Component { render() { const { loading, loadingDocuments } = this.state; - var rentalRequest = this.props.rentalRequest || {}; + const rentalRequest = this.props.rentalRequest || {}; + const dispatch = this.props.dispatch; - var viewOnly = !rentalRequest.projectId; - var canEditRequest = !viewOnly && rentalRequest.status !== Constant.RENTAL_REQUEST_STATUS_CODE_COMPLETED; + const viewOnly = !rentalRequest.projectId; + const canEditRequest = !viewOnly && rentalRequest.status !== Constant.RENTAL_REQUEST_STATUS_CODE_COMPLETED; return (
@@ -569,8 +573,8 @@ class RentalRequestsDetail extends React.Component { id={String(this.props.match.params.rentalRequestId)} show={this.state.showNotesDialog} notes={this.props.rentalRequest.notes} - getNotes={Api.getRentalRequestNotes} - saveNote={Api.addRentalRequestNote} + getNotes={(rentalRequestId) => dispatch(Api.getRentalRequestNotes(rentalRequestId))} + saveNote={(rentalRequestId, note) => dispatch(Api.addRentalRequestNote(rentalRequestId, note))} onClose={this.closeNotesDialog} /> )} @@ -579,11 +583,11 @@ class RentalRequestsDetail extends React.Component { } } -function mapStateToProps(state) { - return { - rentalRequest: activeRentalRequestSelector(state), - documents: state.models.documents, - }; -} +const mapStateToProps = (state) => ({ + rentalRequest: activeRentalRequestSelector(state), + documents: state.models.documents, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(RentalRequestsDetail); +export default connect(mapStateToProps, mapDispatchToProps)(RentalRequestsDetail); diff --git a/client/src/js/views/Roles.jsx b/client/src/js/views/Roles.jsx index fa62b7d71..017ad073e 100644 --- a/client/src/js/views/Roles.jsx +++ b/client/src/js/views/Roles.jsx @@ -9,7 +9,6 @@ import _ from 'lodash'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import PageHeader from '../components/ui/PageHeader.jsx'; import SearchBar from '../components/ui/SearchBar.jsx'; @@ -54,14 +53,14 @@ class Roles extends React.Component { fetch = () => { this.setState({ loading: true }); - Api.searchRoles().finally(() => { + this.props.dispatch(Api.searchRoles()).finally(() => { this.setState({ loading: false }); }); }; updateSearchState = (state, callback) => { this.setState({ search: { ...this.state.search, ...state } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_ROLES_SEARCH, roles: this.state.search, }); @@ -73,7 +72,7 @@ class Roles extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_ROLES_UI, roles: this.state.ui }); + this.props.dispatch({ type: Action.UPDATE_ROLES_UI, roles: this.state.ui }); if (callback) { callback(); } @@ -81,7 +80,7 @@ class Roles extends React.Component { }; delete = (role) => { - Api.deleteRole(role).then(() => { + this.props.dispatch(Api.deleteRole(role)).then(() => { this.fetch(); }); }; @@ -201,13 +200,13 @@ class Roles extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - roles: state.models.roles, - search: state.search.roles, - ui: state.ui.roles, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + roles: state.models.roles, + search: state.search.roles, + ui: state.ui.roles, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(Roles); +export default connect(mapStateToProps, mapDispatchToProps)(Roles); diff --git a/client/src/js/views/RolesDetail.jsx b/client/src/js/views/RolesDetail.jsx index 97a227313..04c7198a6 100644 --- a/client/src/js/views/RolesDetail.jsx +++ b/client/src/js/views/RolesDetail.jsx @@ -9,7 +9,6 @@ import _ from 'lodash'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import FormInputControl from '../components/FormInputControl.jsx'; import Spinner from '../components/Spinner.jsx'; @@ -52,8 +51,8 @@ class RolesDetail extends React.Component { componentDidMount() { if (this.state.isNew) { // Clear the role and permissions store - store.dispatch({ type: Action.UPDATE_ROLE, role: {} }); - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_ROLE, role: {} }); + this.props.dispatch({ type: Action.UPDATE_ROLE_PERMISSIONS, rolePermissions: {}, }); @@ -63,8 +62,8 @@ class RolesDetail extends React.Component { } fetch = () => { - var rolePromise = Api.getRole(this.props.match.params.roleId); - var permissionsPromise = Api.getRolePermissions(this.props.match.params.roleId); + const rolePromise = this.props.dispatch(Api.getRole(this.props.match.params.roleId)); + const permissionsPromise = this.props.dispatch(Api.getRolePermissions(this.props.match.params.roleId)); this.setState({ loading: true }); Promise.all([rolePromise, permissionsPromise]).then(() => { @@ -139,12 +138,12 @@ class RolesDetail extends React.Component { savePermissions = () => { if (this.didChangePermissions()) { - Api.updateRolePermissions( + this.props.dispatch(Api.updateRolePermissions( this.props.role.id, _.map(this.state.selectedPermissionIds, (id) => { return { id: id }; }) - ).then(() => { + )).then(() => { this.returnToList(); }); } else { @@ -162,20 +161,20 @@ class RolesDetail extends React.Component { if (this.isValid()) { if (this.didChangeRole()) { if (this.state.isNew) { - Api.addRole({ + this.props.dispatch(Api.addRole({ name: this.state.name, description: this.state.description, - }).then(() => { + })).then(() => { this.savePermissions(); }); } else { - Api.updateRole({ + this.props.dispatch(Api.updateRole({ ...this.props.role, ...{ name: this.state.name, description: this.state.description, }, - }).then(() => { + })).then(() => { this.savePermissions(); }); } @@ -315,13 +314,13 @@ class RolesDetail extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - role: state.models.role, - rolePermissions: state.models.rolePermissions, - permissions: state.lookups.permissions, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + role: state.models.role, + rolePermissions: state.models.rolePermissions, + permissions: state.lookups.permissions, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(RolesDetail); +export default connect(mapStateToProps, mapDispatchToProps)(RolesDetail); diff --git a/client/src/js/views/Rollover.jsx b/client/src/js/views/Rollover.jsx index ebbb9d19a..63f98d924 100644 --- a/client/src/js/views/Rollover.jsx +++ b/client/src/js/views/Rollover.jsx @@ -35,10 +35,10 @@ class Rollover extends React.Component { } componentDidMount() { - var user = this.props.currentUser; - var status = this.props.rolloverStatus; + const user = this.props.currentUser; + const status = this.props.rolloverStatus; - Api.getRolloverStatus(this.props.currentUser.district.id).then(() => { + this.props.dispatch(Api.getRolloverStatus(this.props.currentUser.district.id)).then(() => { this.setState({ loading: false }); if (!user.hasPermission(Constant.PERMISSION_DISTRICT_ROLLOVER) && !status.rolloverActive) { @@ -65,8 +65,9 @@ class Rollover extends React.Component { refreshStatus = () => { const districtId = this.props.currentUser.district.id; + const dispatch = this.props.dispatch; - Api.getRolloverStatus(districtId).then(() => { + dispatch(Api.getRolloverStatus(districtId)).then(() => { const status = this.props.rolloverStatus; if (!status.rolloverActive && this.state.refreshStatusTimerId !== null) { @@ -76,17 +77,17 @@ class Rollover extends React.Component { if (status.rolloverComplete) { // refresh fiscal years - Api.getFiscalYears(districtId); + dispatch(Api.getFiscalYears(districtId)); } }); }; initiateRollover = () => { - Api.initiateRollover(this.props.currentUser.district.id); + this.props.dispatch(Api.initiateRollover(this.props.currentUser.district.id)); }; dismissRolloverNotice = () => { - Api.dismissRolloverMessage(this.props.currentUser.district.id); + this.props.dispatch(Api.dismissRolloverMessage(this.props.currentUser.district.id)); }; updateState = (state, callback) => { @@ -237,11 +238,11 @@ class Rollover extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - rolloverStatus: state.lookups.rolloverStatus, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + rolloverStatus: state.lookups.rolloverStatus, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(Rollover); +export default connect(mapStateToProps, mapDispatchToProps)(Rollover); diff --git a/client/src/js/views/SeniorityList.jsx b/client/src/js/views/SeniorityList.jsx index 3d3dc3c6d..ffa7c869b 100644 --- a/client/src/js/views/SeniorityList.jsx +++ b/client/src/js/views/SeniorityList.jsx @@ -35,7 +35,7 @@ class SeniorityList extends React.Component { } fetch = () => { - Api.getDistrictEquipmentTypes(); + this.props.dispatch(Api.getDistrictEquipmentTypes()); }; updateState = (state) => { @@ -60,20 +60,21 @@ class SeniorityList extends React.Component { .value(); }; - getRotationList = (counterCopy) => { + getRotationList = async (counterCopy) => { const filename = 'SeniorityList-' + formatDateTimeUTCToLocal(new Date(), Constant.DATE_TIME_FILENAME) + (counterCopy ? '-(CounterCopy)' : '') + '.docx'; - Api.equipmentSeniorityListDoc(this.state.selectedLocalAreaIds, this.state.selectedEquipmentTypeIds, counterCopy) - .then((res) => { - saveAs(res, filename); - }) - .catch((error) => { - console.log(error); - }); + try { + const res = await this.props.dispatch( + Api.equipmentSeniorityListDoc(this.state.selectedLocalAreaIds, this.state.selectedEquipmentTypeIds, counterCopy)); + + saveAs(res, filename); + } catch(error) { + console.log(error); + } }; render() { @@ -124,12 +125,12 @@ class SeniorityList extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - districtEquipmentTypes: state.lookups.districtEquipmentTypes, - localAreas: state.lookups.localAreas, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + districtEquipmentTypes: state.lookups.districtEquipmentTypes, + localAreas: state.lookups.localAreas, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(SeniorityList); +export default connect(mapStateToProps, mapDispatchToProps)(SeniorityList); diff --git a/client/src/js/views/StatusLetters.jsx b/client/src/js/views/StatusLetters.jsx index 9874f1210..4d23a9322 100644 --- a/client/src/js/views/StatusLetters.jsx +++ b/client/src/js/views/StatusLetters.jsx @@ -30,7 +30,7 @@ class StatusLetters extends React.Component { } componentDidMount() { - Api.getOwnersLite(); + this.props.dispatch(Api.getOwnersLite()); } updateState = (state, callback) => { @@ -41,32 +41,30 @@ class StatusLetters extends React.Component { }); }; - getStatusLetters = () => { + getStatusLetters = async () => { const filename = 'StatusLetters-' + formatDateTimeUTCToLocal(new Date(), Constant.DATE_TIME_FILENAME) + '.docx'; - Api.getStatusLettersDoc({ - localAreas: this.state.localAreaIds, - owners: this.state.ownerIds, - }) - .then((res) => { - saveAs(res, filename); - }) - .catch((error) => { - console.log(error); - }); + try { + const res = await this.props.dispatch(Api.getStatusLettersDoc({ + localAreas: this.state.localAreaIds, + owners: this.state.ownerIds, + })); + saveAs(res, filename); + } catch(error) { + console.log(error); + } }; - getMailingLabel = () => { + getMailingLabel = async () => { const filename = 'MailingLabels-' + formatDateTimeUTCToLocal(new Date(), Constant.DATE_TIME_FILENAME) + '.docx'; - Api.getMailingLabelsDoc({ - localAreas: this.state.localAreaIds, - owners: this.state.ownerIds, - }) - .then((res) => { - saveAs(res, filename); - }) - .catch((error) => { - console.log(error); - }); + try { + const res = await this.props.dispatch(Api.getMailingLabelsDoc({ + localAreas: this.state.localAreaIds, + owners: this.state.ownerIds, + })); + saveAs(res, filename); + } catch(error) { + console.log(error); + } }; matchesLocalAreaFilter = (localAreaId) => { @@ -138,11 +136,11 @@ class StatusLetters extends React.Component { } } -function mapStateToProps(state) { - return { - localAreas: state.lookups.localAreas, - owners: state.lookups.owners.lite, - }; -} +const mapStateToProps = (state) => ({ + localAreas: state.lookups.localAreas, + owners: state.lookups.owners.lite, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(StatusLetters); +export default connect(mapStateToProps, mapDispatchToProps)(StatusLetters); diff --git a/client/src/js/views/TimeEntry.jsx b/client/src/js/views/TimeEntry.jsx index 3bfedc13e..c8fa6574a 100644 --- a/client/src/js/views/TimeEntry.jsx +++ b/client/src/js/views/TimeEntry.jsx @@ -11,7 +11,6 @@ import TimeEntryDialog from './dialogs/TimeEntryDialog.jsx'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import AddButtonContainer from '../components/ui/AddButtonContainer.jsx'; import PageHeader from '../components/ui/PageHeader.jsx'; @@ -60,9 +59,9 @@ class TimeEntry extends React.Component { } componentDidMount() { - Api.getProjectsCurrentFiscal(); - Api.getEquipmentTs(); - Api.getOwnersLiteTs(); + this.props.dispatch(Api.getProjectsCurrentFiscal()); + this.props.dispatch(Api.getEquipmentTs()); + this.props.dispatch(Api.getOwnersLiteTs()); // If this is the first load, then look for a default favourite if (_.isEmpty(this.props.search)) { @@ -96,7 +95,7 @@ class TimeEntry extends React.Component { }; fetch = () => { - Api.searchTimeEntries(this.buildSearchParams()); + this.props.dispatch(Api.searchTimeEntries(this.buildSearchParams())); }; search = (e) => { @@ -113,17 +112,17 @@ class TimeEntry extends React.Component { }; this.setState({ search: defaultSearchParameters }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_TIME_ENTRIES_SEARCH, timeEntries: this.state.search, }); - store.dispatch({ type: Action.CLEAR_TIME_ENTRIES }); + this.props.dispatch({ type: Action.CLEAR_TIME_ENTRIES }); }); }; updateSearchState = (state, callback) => { this.setState({ search: { ...this.state.search, ...state, ...{ loaded: true } } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_TIME_ENTRIES_SEARCH, timeEntries: this.state.search, }); @@ -135,7 +134,7 @@ class TimeEntry extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_TIME_ENTRIES_UI, timeEntries: this.state.ui, }); @@ -439,17 +438,17 @@ class TimeEntry extends React.Component { } } -function mapStateToProps(state) { - return { - projects: state.lookups.projectsCurrentFiscal, - localAreas: state.lookups.localAreas, - owners: state.lookups.owners.ts, - equipment: state.lookups.equipment.ts, - timeEntries: state.models.timeEntries, - favourites: state.models.favourites.timeEntry, - search: state.search.timeEntries, - ui: state.ui.timeEntries, - }; -} +const mapStateToProps = (state) => ({ + projects: state.lookups.projectsCurrentFiscal, + localAreas: state.lookups.localAreas, + owners: state.lookups.owners.ts, + equipment: state.lookups.equipment.ts, + timeEntries: state.models.timeEntries, + favourites: state.models.favourites.timeEntry, + search: state.search.timeEntries, + ui: state.ui.timeEntries, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(TimeEntry); +export default connect(mapStateToProps, mapDispatchToProps)(TimeEntry); diff --git a/client/src/js/views/TopNav.jsx b/client/src/js/views/TopNav.jsx index 57a9d804e..cc8ce8a57 100644 --- a/client/src/js/views/TopNav.jsx +++ b/client/src/js/views/TopNav.jsx @@ -42,22 +42,22 @@ class TopNav extends React.Component { showNav: true, }; - updateUserDistrict = (state) => { - var district = _.find(this.props.currentUserDistricts.data, (district) => { + updateUserDistrict = async (state) => { + const district = _.find(this.props.currentUserDistricts.data, (district) => { return district.district.id === parseInt(state.districtId); }); - Api.switchUserDistrict(district.id).then(() => { - this.props.history.push(Constant.HOME_PATHNAME); - window.location.reload(); - }); + await this.props.dispatch(Api.switchUserDistrict(district.id)); + this.props.history.push(Constant.HOME_PATHNAME); + window.location.reload(); }; dismissRolloverNotice = () => { - Api.dismissRolloverMessage(this.props.currentUser.district.id); + this.props.dispatch(Api.dismissRolloverMessage(this.props.currentUser.district.id)); }; render() { - var userDistricts = _.map(this.props.currentUserDistricts.data, (district) => { + const dispatch = this.props.dispatch; + const userDistricts = _.map(this.props.currentUserDistricts.data, (district) => { return { ...district, districtName: district.district.name, @@ -65,9 +65,9 @@ class TopNav extends React.Component { }; }); - var navigationDisabled = this.props.rolloverStatus.rolloverActive; + const navigationDisabled = this.props.rolloverStatus.rolloverActive; - var environmentClass = ''; + let environmentClass = ''; if (this.props.currentUser.environment === 'Development') { environmentClass = 'env-dev'; } else if (this.props.currentUser.environment === 'Test') { @@ -171,13 +171,13 @@ class TopNav extends React.Component { @@ -283,13 +283,13 @@ class TopNav extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - showWorkingIndicator: state.ui.requests.waiting, - currentUserDistricts: state.models.currentUserDistricts, - rolloverStatus: state.lookups.rolloverStatus, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + showWorkingIndicator: state.ui.requests.waiting, + currentUserDistricts: state.models.currentUserDistricts, + rolloverStatus: state.lookups.rolloverStatus, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps, null, null, { pure: false })(withRouter(TopNav)); +export default connect(mapStateToProps, mapDispatchToProps, null, { pure: false })(withRouter(TopNav)); diff --git a/client/src/js/views/Users.jsx b/client/src/js/views/Users.jsx index 3c2ddc720..7fa752fdf 100644 --- a/client/src/js/views/Users.jsx +++ b/client/src/js/views/Users.jsx @@ -10,7 +10,6 @@ import UsersEditDialog from './dialogs/UsersEditDialog.jsx'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import AddButtonContainer from '../components/ui/AddButtonContainer.jsx'; import PageHeader from '../components/ui/PageHeader.jsx'; @@ -81,7 +80,7 @@ class Users extends React.Component { } fetch = () => { - Api.searchUsers(this.buildSearchParams()); + this.props.dispatch(Api.searchUsers(this.buildSearchParams())); }; search = (e) => { @@ -97,14 +96,14 @@ class Users extends React.Component { }; this.setState({ search: defaultSearchParameters }, () => { - store.dispatch({ type: Action.UPDATE_USERS_SEARCH, users: this.state.search }); - store.dispatch({ type: Action.CLEAR_USERS }); + this.props.dispatch({ type: Action.UPDATE_USERS_SEARCH, users: this.state.search }); + this.props.dispatch({ type: Action.CLEAR_USERS }); }); }; updateSearchState = (state, callback) => { this.setState({ search: { ...this.state.search, ...state, ...{ loaded: true } } }, () => { - store.dispatch({ type: Action.UPDATE_USERS_SEARCH, users: this.state.search }); + this.props.dispatch({ type: Action.UPDATE_USERS_SEARCH, users: this.state.search }); if (callback) { callback(); } @@ -113,7 +112,7 @@ class Users extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_USERS_UI, users: this.state.ui }); + this.props.dispatch({ type: Action.UPDATE_USERS_UI, users: this.state.ui }); if (callback) { callback(); } @@ -125,7 +124,7 @@ class Users extends React.Component { }; delete = (user) => { - Api.deleteUser(user).then(() => { + this.props.dispatch(Api.deleteUser(user)).then(() => { this.fetch(); }); }; @@ -304,16 +303,16 @@ class Users extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - users: state.models.users, - user: state.models.user, - districts: state.lookups.districts, - favourites: state.models.favourites.user, - search: state.search.users, - ui: state.ui.users, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + users: state.models.users, + user: state.models.user, + districts: state.lookups.districts, + favourites: state.models.favourites.user, + search: state.search.users, + ui: state.ui.users, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(Users); +export default connect(mapStateToProps, mapDispatchToProps)(Users); diff --git a/client/src/js/views/UsersDetail.jsx b/client/src/js/views/UsersDetail.jsx index 231437a7d..042068620 100644 --- a/client/src/js/views/UsersDetail.jsx +++ b/client/src/js/views/UsersDetail.jsx @@ -23,7 +23,6 @@ import DistrictEditDialog from './dialogs/DistrictEditDialog.jsx'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import CheckboxControl from '../components/CheckboxControl.jsx'; import ColDisplay from '../components/ColDisplay.jsx'; @@ -77,7 +76,7 @@ class UsersDetail extends React.Component { // if new user if (this.props.match.params.userId === '0') { // Clear the user store - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_USER, user: { id: 0, @@ -102,8 +101,8 @@ class UsersDetail extends React.Component { fetch = () => { this.setState({ loading: true }); Promise.all([ - Api.getUser(this.props.match.params.userId), - Api.getUserDistricts(this.props.match.params.userId), + this.props.dispatch(Api.getUser(this.props.match.params.userId)), + this.props.dispatch(Api.getUserDistricts(this.props.match.params.userId)), ]).then(() => { this.setState({ loading: false }); }); @@ -111,7 +110,7 @@ class UsersDetail extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_USER_ROLES_UI, userRoles: this.state.ui }); + this.props.dispatch({ type: Action.UPDATE_USER_ROLES_UI, userRoles: this.state.ui }); if (callback) { callback(); } @@ -157,7 +156,7 @@ class UsersDetail extends React.Component { }; }); - Api.updateUserRoles(this.props.user.id, userRoles); + this.props.dispatch(Api.updateUserRoles(this.props.user.id, userRoles)); this.closeUserRoleDialog(); }; @@ -183,14 +182,14 @@ class UsersDetail extends React.Component { }; deleteDistrict = (district) => { - Api.deleteUserDistrict(district).then((response) => { + this.props.dispatch(Api.deleteUserDistrict(district)).then((response) => { this.updateCurrentUserDistricts(response.data); }); }; updateCurrentUserDistricts = (districts) => { if (this.props.user.id === this.props.currentUser.id) { - store.dispatch({ type: Action.CURRENT_USER_DISTRICTS, currentUserDistricts: districts }); + this.props.dispatch({ type: Action.CURRENT_USER_DISTRICTS, currentUserDistricts: districts }); } }; @@ -570,14 +569,14 @@ class ExpireOverlay extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - user: state.models.user, - ui: state.ui.userRoles, - userDistricts: state.models.userDistricts, - districts: state.lookups.districts, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + user: state.models.user, + ui: state.ui.userRoles, + userDistricts: state.models.userDistricts, + districts: state.lookups.districts, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(UsersDetail); +export default connect(mapStateToProps, mapDispatchToProps)(UsersDetail); diff --git a/client/src/js/views/Version.jsx b/client/src/js/views/Version.jsx index f96f935ca..9a0cbb229 100644 --- a/client/src/js/views/Version.jsx +++ b/client/src/js/views/Version.jsx @@ -35,30 +35,29 @@ class Version extends React.Component { componentDidMount() { this.setState({ loading: true }); - Api.getVersion().finally(() => { + this.props.dispatch(Api.getVersion()).finally(() => { this.fetchLocal().finally(() => { this.setState({ loading: false }); }); }); } - fetchLocal = () => { - return request('buildinfo.html', { silent: true }) - .then((xhr) => { - if (xhr.status === 200) { - const parser = new DOMParser(); - const doc = parser.parseFromString(xhr.responseText, 'text/html'); - - this.setState({ - buildTime: doc.getElementById('buildtime').dataset.buildtime, - version: doc.getElementById('version').textContent, - commit: doc.getElementById('commit').textContent, - }); - } - }) - .catch((err) => { - console.error('Failed to find buildinfo: ', err); - }); + fetchLocal = async () => { + try { + const xhr = await this.props.dispatch(request('buildinfo.html', { silent: true })); + if (xhr.status === 200) { + const parser = new DOMParser(); + const doc = parser.parseFromString(xhr.responseText, 'text/html'); + + this.setState({ + buildTime: doc.getElementById('buildtime').dataset.buildtime, + version: doc.getElementById('version').textContent, + commit: doc.getElementById('commit').textContent, + }); + } + } catch(err) { + console.error('Failed to find buildinfo: ', err); + }; }; showRaw = (e) => { @@ -188,10 +187,10 @@ class Version extends React.Component { } } -function mapStateToProps(state) { - return { - version: state.version, - }; -} +const mapStateToProps = (state) => ({ + version: state.version, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(Version); +export default connect(mapStateToProps, mapDispatchToProps)(Version); diff --git a/client/src/js/views/WcbCglCoverage.jsx b/client/src/js/views/WcbCglCoverage.jsx index 1e22bd292..6074d6fcb 100644 --- a/client/src/js/views/WcbCglCoverage.jsx +++ b/client/src/js/views/WcbCglCoverage.jsx @@ -9,7 +9,6 @@ import Moment from 'moment'; import * as Action from '../actionTypes'; import * as Api from '../api'; import * as Constant from '../constants'; -import store from '../store'; import PageHeader from '../components/ui/PageHeader.jsx'; import SearchBar from '../components/ui/SearchBar.jsx'; @@ -77,7 +76,7 @@ class WcbCglCoverage extends React.Component { }; componentDidMount() { - Api.getOwnersLite(); + this.props.dispatch(Api.getOwnersLite()); // If this is the first load, then look for a default favourite if (_.isEmpty(this.props.search)) { @@ -89,7 +88,7 @@ class WcbCglCoverage extends React.Component { } fetch = () => { - Api.searchOwnersCoverage(this.buildSearchParams()); + this.props.dispatch(Api.searchOwnersCoverage(this.buildSearchParams())); }; search = (e) => { @@ -106,17 +105,17 @@ class WcbCglCoverage extends React.Component { }; this.setState({ search: defaultSearchParameters }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_OWNERS_COVERAGE_SEARCH, ownersCoverage: this.state.search, }); - store.dispatch({ type: Action.CLEAR_OWNERS_COVERAGE }); + this.props.dispatch({ type: Action.CLEAR_OWNERS_COVERAGE }); }); }; updateSearchState = (state, callback) => { this.setState({ search: { ...this.state.search, ...state, ...{ loaded: true } } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_OWNERS_COVERAGE_SEARCH, ownersCoverage: this.state.search, }); @@ -128,7 +127,7 @@ class WcbCglCoverage extends React.Component { updateUIState = (state, callback) => { this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ + this.props.dispatch({ type: Action.UPDATE_OWNERS_COVERAGE_UI, ownersCoverage: this.state.ui, }); @@ -316,15 +315,15 @@ class WcbCglCoverage extends React.Component { } } -function mapStateToProps(state) { - return { - localAreas: state.lookups.localAreas, - owners: state.lookups.owners.lite, - ownersCoverage: state.models.ownersCoverage, - favourites: state.models.favourites.ownersCoverage, - search: state.search.ownersCoverage, - ui: state.ui.ownersCoverage, - }; -} +const mapStateToProps = (state) => ({ + localAreas: state.lookups.localAreas, + owners: state.lookups.owners.lite, + ownersCoverage: state.models.ownersCoverage, + favourites: state.models.favourites.ownersCoverage, + search: state.search.ownersCoverage, + ui: state.ui.ownersCoverage, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(WcbCglCoverage); +export default connect(mapStateToProps, mapDispatchToProps)(WcbCglCoverage); diff --git a/client/src/js/views/dialogs/AttachmentAddDialog.jsx b/client/src/js/views/dialogs/AttachmentAddDialog.jsx index c714d655d..1328ba594 100644 --- a/client/src/js/views/dialogs/AttachmentAddDialog.jsx +++ b/client/src/js/views/dialogs/AttachmentAddDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { FormGroup, FormText, FormLabel, Button } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -89,25 +90,23 @@ class AttachmentAddDialog extends React.Component { } }; - formSubmitted = () => { + formSubmitted = async () => { if (this.isValid()) { if (this.didChange()) { this.setState({ isSaving: true }); + const dispatch = this.props.dispatch; const attachmentTypeNames = this.state.forms.map((form) => form.typeName); - const promise = Api.addPhysicalAttachments(this.props.equipment.id, attachmentTypeNames); - - promise.then(() => { - attachmentTypeNames.forEach((typeName) => { - Log.equipmentAttachmentAdded(this.props.equipment, typeName); - }); - this.setState({ isSaving: false }); - if (this.props.onSave) { - this.props.onSave(); - } - this.props.onClose(); + await dispatch(Api.addPhysicalAttachments(this.props.equipment.id, attachmentTypeNames)); + attachmentTypeNames.forEach(async (typeName) => { + await dispatch(Log.equipmentAttachmentAdded(this.props.equipment, typeName)); }); + this.setState({ isSaving: false }); + if (this.props.onSave) { + this.props.onSave(); + } + this.props.onClose(); } else { this.props.onClose(); } @@ -158,4 +157,6 @@ class AttachmentAddDialog extends React.Component { } } -export default AttachmentAddDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(AttachmentAddDialog); diff --git a/client/src/js/views/dialogs/AttachmentEditDialog.jsx b/client/src/js/views/dialogs/AttachmentEditDialog.jsx index 711f278b0..7cf90d6f9 100644 --- a/client/src/js/views/dialogs/AttachmentEditDialog.jsx +++ b/client/src/js/views/dialogs/AttachmentEditDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { FormGroup, FormText, FormLabel } from 'react-bootstrap'; @@ -56,11 +57,12 @@ class AttachmentEditDialog extends React.Component { return valid; }; - formSubmitted = () => { + formSubmitted = async () => { if (this.isValid()) { if (this.didChange()) { this.setState({ isSaving: true }); + const dispatch = this.props.dispatch; const attachment = { id: this.props.attachment.id, typeName: this.state.typeName, @@ -68,16 +70,13 @@ class AttachmentEditDialog extends React.Component { equipment: { id: this.props.equipment.id }, }; - const promise = Api.updatePhysicalAttachment(attachment); - - promise.then(() => { - Log.equipmentAttachmentUpdated(this.props.equipment, attachment.typeName); - this.setState({ isSaving: false }); - if (this.props.onSave) { - this.props.onSave(); - } - this.props.onClose(); - }); + await dispatch(Api.updatePhysicalAttachment(attachment)); + await dispatch(Log.equipmentAttachmentUpdated(this.props.equipment, attachment.typeName)); + this.setState({ isSaving: false }); + if (this.props.onSave) { + this.props.onSave(); + } + this.props.onClose(); } else { this.props.onClose(); } @@ -109,4 +108,6 @@ class AttachmentEditDialog extends React.Component { } } -export default AttachmentEditDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(AttachmentEditDialog); diff --git a/client/src/js/views/dialogs/CloneDialog.jsx b/client/src/js/views/dialogs/CloneDialog.jsx index c65bc11ce..8b52d1224 100644 --- a/client/src/js/views/dialogs/CloneDialog.jsx +++ b/client/src/js/views/dialogs/CloneDialog.jsx @@ -39,8 +39,8 @@ class CloneDialog extends React.Component { } componentDidMount() { - var getProjectRentalAgreementsPromise = Api.getProjectRentalAgreements(this.props.rentalAgreement.project.id); - var getEquipmentRentalAgreementsPromise = Api.getEquipmentRentalAgreements(this.props.rentalAgreement.equipment.id); + const getProjectRentalAgreementsPromise = this.props.dispatch(Api.getProjectRentalAgreements(this.props.rentalAgreement.project.id)); + const getEquipmentRentalAgreementsPromise = this.props.dispatch(Api.getEquipmentRentalAgreements(this.props.rentalAgreement.equipment.id)); this.setState({ loading: true }); return Promise.all([getProjectRentalAgreementsPromise, getEquipmentRentalAgreementsPromise]).finally(() => { this.setState({ loading: false }); @@ -72,7 +72,7 @@ class CloneDialog extends React.Component { if (this.didChange()) { this.setState({ isSaving: true }); - var data = { + const data = { projectId: this.props.rentalAgreement.project.id, agreementToCloneId: parseInt(this.state.rentalAgreementId, 10), rentalAgreementId: this.props.rentalAgreement.id, @@ -81,8 +81,8 @@ class CloneDialog extends React.Component { const promise = this.state.type === Constant.BY_EQUIPMENT - ? Api.cloneEquipmentRentalAgreement(data) - : Api.cloneProjectRentalAgreement(data); + ? this.props.dispatch(Api.cloneEquipmentRentalAgreement(data)) + : this.props.dispatch(Api.cloneProjectRentalAgreement(data)); promise .then(() => { @@ -218,11 +218,11 @@ class CloneDialog extends React.Component { } } -function mapStateToProps(state) { - return { - projectRentalAgreements: state.models.projectRentalAgreements, - equipmentRentalAgreements: state.models.equipmentRentalAgreements, - }; -} +const mapStateToProps = (state) => ({ + projectRentalAgreements: state.models.projectRentalAgreements, + equipmentRentalAgreements: state.models.equipmentRentalAgreements, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(CloneDialog); +export default connect(mapStateToProps, mapDispatchToProps)(CloneDialog); diff --git a/client/src/js/views/dialogs/ConditionAddEditDialog.jsx b/client/src/js/views/dialogs/ConditionAddEditDialog.jsx index 85a911025..a42cdf7aa 100644 --- a/client/src/js/views/dialogs/ConditionAddEditDialog.jsx +++ b/client/src/js/views/dialogs/ConditionAddEditDialog.jsx @@ -86,7 +86,7 @@ class ConditionAddEditDialog extends React.Component { }); }; - formSubmitted = () => { + formSubmitted = async () => { if (this.isValid()) { if (this.didChange()) { this.setState({ isSaving: true }); @@ -100,15 +100,14 @@ class ConditionAddEditDialog extends React.Component { district: { id: this.props.currentUser.district.id }, }; - const promise = this.state.isNew ? Api.addCondition(condition) : Api.updateCondition(condition); + const promise = this.state.isNew ? Api.addCondition : Api.updateCondition; - promise.then(() => { - this.setState({ isSaving: false }); - if (this.props.onSave) { - this.props.onSave(); - } - this.props.onClose(); - }); + await this.props.dispatch(promise(condition)); + this.setState({ isSaving: false }); + if (this.props.onSave) { + this.props.onSave(); + } + this.props.onClose(); } else { this.props.onClose(); } @@ -155,10 +154,10 @@ class ConditionAddEditDialog extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(ConditionAddEditDialog); +export default connect(mapStateToProps, mapDispatchToProps)(ConditionAddEditDialog); diff --git a/client/src/js/views/dialogs/DistrictEditDialog.jsx b/client/src/js/views/dialogs/DistrictEditDialog.jsx index 20e477d5a..b1ebca34f 100644 --- a/client/src/js/views/dialogs/DistrictEditDialog.jsx +++ b/client/src/js/views/dialogs/DistrictEditDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import _ from 'lodash'; import { FormGroup, FormText } from 'react-bootstrap'; @@ -84,7 +85,8 @@ class DistrictEditDialog extends React.Component { isPrimary: this.state.isPrimary, }; - const promise = this.state.isNew ? Api.addUserDistrict(district) : Api.editUserDistrict(district); + const promise = this.state.isNew ? + this.props.dispatch(Api.addUserDistrict(district)) : this.props.dispatch(Api.editUserDistrict(district)); promise.then((response) => { this.setState({ isSaving: false }); @@ -147,4 +149,6 @@ class DistrictEditDialog extends React.Component { } } -export default DistrictEditDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(DistrictEditDialog); diff --git a/client/src/js/views/dialogs/DistrictEquipmentTypeAddEditDialog.jsx b/client/src/js/views/dialogs/DistrictEquipmentTypeAddEditDialog.jsx index ce6012e20..1bc93e8ac 100644 --- a/client/src/js/views/dialogs/DistrictEquipmentTypeAddEditDialog.jsx +++ b/client/src/js/views/dialogs/DistrictEquipmentTypeAddEditDialog.jsx @@ -41,7 +41,7 @@ class DistrictEquipmentTypeAddEditDialog extends React.Component { } componentDidMount() { - Api.getEquipmentTypes(); + this.props.dispatch(Api.getEquipmentTypes()); } updateState = (state, callback) => { @@ -95,7 +95,7 @@ class DistrictEquipmentTypeAddEditDialog extends React.Component { return valid; }; - formSubmitted = () => { + formSubmitted = async () => { if (this.isValid()) { if (this.didChange()) { this.setState({ isSaving: true }); @@ -108,18 +108,16 @@ class DistrictEquipmentTypeAddEditDialog extends React.Component { district: { id: this.props.currentUser.district.id }, }; - const promise = - equipmentType.id !== 0 - ? Api.updateDistrictEquipmentType(equipmentType) - : Api.addDistrictEquipmentType(equipmentType); - - promise.then(() => { - this.setState({ isSaving: false }); - if (this.props.onSave) { - this.props.onSave(); - } - this.props.onClose(); - }); + const promise = equipmentType.id !== 0 ? + Api.updateDistrictEquipmentType : + Api.addDistrictEquipmentType; + + await this.props.dispatch(promise(equipmentType)); + this.setState({ isSaving: false }); + if (this.props.onSave) { + this.props.onSave(); + } + this.props.onClose(); } else { this.props.onClose(); } @@ -127,7 +125,7 @@ class DistrictEquipmentTypeAddEditDialog extends React.Component { }; render() { - var equipmentTypes = _.sortBy(this.props.equipmentTypes.data, 'blueBookSection'); + let equipmentTypes = _.sortBy(this.props.equipmentTypes.data, 'blueBookSection'); return ( ({ + currentUser: state.user, + equipmentTypes: state.lookups.equipmentTypes, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(DistrictEquipmentTypeAddEditDialog); +export default connect(mapStateToProps, mapDispatchToProps)(DistrictEquipmentTypeAddEditDialog); diff --git a/client/src/js/views/dialogs/DocumentsListDialog.jsx b/client/src/js/views/dialogs/DocumentsListDialog.jsx index 642ee539c..a4e1b607e 100644 --- a/client/src/js/views/dialogs/DocumentsListDialog.jsx +++ b/client/src/js/views/dialogs/DocumentsListDialog.jsx @@ -14,7 +14,6 @@ import { request, buildApiPath } from '../../utils/http'; import * as Action from '../../actionTypes'; import * as Api from '../../api'; import * as Constant from '../../constants'; -import store from '../../store'; import DeleteButton from '../../components/DeleteButton.jsx'; import ModalDialog from '../../components/ModalDialog.jsx'; @@ -60,8 +59,9 @@ class DocumentsListDialog extends React.Component { } updateUIState = (state, callback) => { + const dispatch = this.props.dispatch; this.setState({ ui: { ...this.state.ui, ...state } }, () => { - store.dispatch({ type: Action.UPDATE_DOCUMENTS_UI, documents: this.state.ui }); + dispatch({ type: Action.UPDATE_DOCUMENTS_UI, documents: this.state.ui }); if (callback) { callback(); } @@ -81,48 +81,47 @@ class DocumentsListDialog extends React.Component { }; formatDocuments = () => { - var documents = _.map(this.props.documents, (document) => { + const documents = _.map(this.props.documents, (document) => { return { ...document, formattedTimestamp: formatDateTime(document.lastUpdateTimestamp, Constant.DATE_TIME_LOG), }; }); this.setState({ - documents: documents, + documents, }); }; - deleteDocument = (document) => { - Api.deleteDocument(document).then(() => { - this.props.parent.documentDeleted(this.props.parent, document); - return this.fetch(); - }); + deleteDocument = async (document) => { + await this.props.dispatch(Api.deleteDocument(document)); + this.props.parent.documentDeleted(this.props.parent, document); + return this.fetch(); }; - downloadDocument = (document) => { + downloadDocument = async (document) => { + const dispatch = this.props.dispatch; let fName = ''; - Api.getDownloadDocument(document) - .getBlob() - .then((res) => { - //use Header content-disposition for the file name - //looks like ""attachment; filename=adobe.pdf; filename*=UTF-8''adobe.pdf"" - console.log(res.getResponseHeader('content-disposition')); - fName = res.getResponseHeader('content-disposition').match(/(?<=filename=)(.*)(?=; filename)/)[0]; - console.log(fName); - saveAs(res.response, fName); - }) - .catch((error) => { - console.log("file name error"); - console.log(error); - let message = error.message.split(`"`)[0].replace('"', ''); //extracts error message without HTML text.Odd issue where I can't detect \ so need to rely on " - this.setState({ uploadError: message }); - }); + try { + const res = await dispatch(Api.getDownloadDocument(document)); + //use Header content-disposition for the file name + //looks like ""attachment; filename=adobe.pdf; filename*=UTF-8''adobe.pdf"" + console.log(res.getResponseHeader('content-disposition')); + fName = res.getResponseHeader('content-disposition').match(/(?<=filename=)(.*)(?=; filename)/)[0]; + console.log(fName); + saveAs(res.response, fName); + } catch (error) { + console.log("file name error"); + console.log(error); + let message = error.message.split(`"`)[0].replace('"', ''); //extracts error message without HTML text.Odd issue where I can't detect \ so need to rely on " + this.setState({ uploadError: message }); + } }; - uploadFiles = (files) => { + uploadFiles = async (files) => { + const dispatch = this.props.dispatch; this.setState({ uploadError: '' }); - var invalidFiles = _.filter(files, (file) => file.size > Constant.MAX_ATTACHMENT_FILE_SIZE); + let invalidFiles = _.filter(files, (file) => file.size > Constant.MAX_ATTACHMENT_FILE_SIZE); if (invalidFiles.length > 0) { this.setState({ uploadError: 'One of the selected files is too large.' }); return; @@ -130,27 +129,27 @@ class DocumentsListDialog extends React.Component { this.setState({ uploadInProgress: true, percentUploaded: 0 }); - var options = { + const options = { method: 'POST', files: [...files], onUploadProgress: (percentComplete) => { - var percent = Math.round(percentComplete); + const percent = Math.round(percentComplete); this.setState({ percentUploaded: percent }); }, }; - this.uploadPromise = request(buildApiPath(this.props.parent.uploadDocumentPath), options).then( - () => { - _.map(files, (file) => { - this.props.parent.documentAdded(this.props.parent, file.name); - }); - this.setState({ uploadInProgress: false, percentUploaded: null }); - this.fetch(); - }, - (err) => { - let message = err.message.split(`"`)[0].replace('"', ''); //extracts error message without HTML text.Odd issue where I can't detect \ so need to rely on " - this.setState({ uploadInProgress: false, uploadError: message }); - } - ); + + try { + this.uploadPromise = await dispatch(request(buildApiPath(this.props.parent.uploadDocumentPath), options)); + _.map(files, (file) => { + this.props.parent.documentAdded(this.props.parent, file.name); + }); + this.setState({ uploadInProgress: false, percentUploaded: null }); + this.fetch(); + } catch(err) { + //extracts error message without HTML text.Odd issue where I can't detect \ so need to rely on " + const message = err.message.split(`"`)[0].replace('"', ''); + this.setState({ uploadInProgress: false, uploadError: message }); + } }; render() { @@ -262,12 +261,12 @@ class DocumentsListDialog extends React.Component { } } -function mapStateToProps(state) { - return { - documents: state.models.documents, - users: state.lookups.users, - ui: state.ui.documents, - }; -} +const mapStateToProps = (state) => ({ + documents: state.models.documents, + users: state.lookups.users, + ui: state.ui.documents, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(DocumentsListDialog); +export default connect(mapStateToProps, mapDispatchToProps)(DocumentsListDialog); diff --git a/client/src/js/views/dialogs/EditFavouritesDialog.jsx b/client/src/js/views/dialogs/EditFavouritesDialog.jsx new file mode 100644 index 000000000..fef95bed6 --- /dev/null +++ b/client/src/js/views/dialogs/EditFavouritesDialog.jsx @@ -0,0 +1,117 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { FormGroup, FormLabel, FormText } from "react-bootstrap"; +import { connect } from "react-redux"; + +import * as Api from "../../api"; +import FormInputControl from "../../components/FormInputControl"; +import CheckboxControl from "../../components/CheckboxControl"; +import FormDialog from "../../components/FormDialog"; +import { isBlank } from "../../utils/string"; + +class EditFavouritesDialog extends React.Component { + static propTypes = { + favourite: PropTypes.object.isRequired, + onSave: PropTypes.func.isRequired, + onClose: PropTypes.func.isRequired, + show: PropTypes.bool, + }; + + constructor(props) { + super(props); + + this.state = { + isSaving: false, + name: props.favourite.name || "", + isDefault: props.favourite.isDefault || false, + nameError: "", + }; + } + + updateState = (state, callback) => { + this.setState(state, callback); + }; + + didChange = () => { + if (this.state.name !== this.props.favourite.name) { + return true; + } + if (this.state.isDefault !== this.props.favourite.isDefault) { + return true; + } + + return false; + }; + + isValid = () => { + if (isBlank(this.state.name)) { + this.setState({ nameError: "Name is required" }); + return false; + } + return true; + }; + + onSubmit = async () => { + if (this.isValid()) { + if (this.didChange()) { + this.setState({ isSaving: true }); + + const favourite = { + ...this.props.favourite, + name: this.state.name, + isDefault: this.state.isDefault, + }; + + try { + if (favourite.id) { + await this.props.dispatch(Api.updateFavourite(favourite)); + } else { + await this.props.dispatch(Api.addFavourite(favourite)); + } + } finally { + this.setState({ isSaving: false }); + this.props.onSave(favourite); + } + } + + this.props.onClose(); + } + }; + + render() { + const { isSaving, name, nameError, isDefault } = this.state; + const { show, onClose } = this.props; + + return ( + + + + Name * + + + {nameError} + + + + ); + } +} + +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(EditFavouritesDialog); \ No newline at end of file diff --git a/client/src/js/views/dialogs/EquipmentAddDialog.jsx b/client/src/js/views/dialogs/EquipmentAddDialog.jsx index 745770b6f..d312f5d2b 100644 --- a/client/src/js/views/dialogs/EquipmentAddDialog.jsx +++ b/client/src/js/views/dialogs/EquipmentAddDialog.jsx @@ -53,7 +53,7 @@ class EquipmentAddDialog extends React.Component { } componentDidMount() { - Api.getDistrictEquipmentTypes(); + this.props.dispatch(Api.getDistrictEquipmentTypes()); } componentDidUpdate(prevProps, prevState) { @@ -160,7 +160,7 @@ class EquipmentAddDialog extends React.Component { return valid; }; - formSubmitted = () => { + formSubmitted = async () => { if (this.isValid()) { if (this.state.duplicateSerialNumberWarning) { // proceed regardless of duplicates @@ -170,30 +170,29 @@ class EquipmentAddDialog extends React.Component { this.setState({ isSaving: true }); - return Api.equipmentDuplicateCheck(0, this.state.serialNumber).then((response) => { - this.setState({ isSaving: false }); - - if (response.data.length > 0) { - const equipmentCodes = response.data.map((district) => { - return district.duplicateEquipment.equipmentCode; - }); - var districts = _.chain(response.data) - .map((district) => district.districtName) - .uniq() - .value(); - const districtsPlural = districts.length === 1 ? 'district' : 'districts'; - this.setState({ - serialNumberError: `Serial number is currently in use for the equipment ${equipmentCodes.join( - ', ' - )}, in the following ${districtsPlural}: ${districts.join(', ')}`, - duplicateSerialNumberWarning: true, - }); - return null; - } else { - this.setState({ duplicateSerialNumberWarning: false }); - return this.saveEquipment(); - } - }); + const response = await this.props.dispatch(Api.equipmentDuplicateCheck(0, this.state.serialNumber));; + this.setState({ isSaving: false }); + + if (response.data.length > 0) { + const equipmentCodes = response.data.map((district) => { + return district.duplicateEquipment.equipmentCode; + }); + let districts = _.chain(response.data) + .map((district) => district.districtName) + .uniq() + .value(); + const districtsPlural = districts.length === 1 ? 'district' : 'districts'; + this.setState({ + serialNumberError: `Serial number is currently in use for the equipment ${equipmentCodes.join( + ', ' + )}, in the following ${districtsPlural}: ${districts.join(', ')}`, + duplicateSerialNumberWarning: true, + }); + return null; + } else { + this.setState({ duplicateSerialNumberWarning: false }); + return this.saveEquipment(); + } } }; @@ -218,7 +217,7 @@ class EquipmentAddDialog extends React.Component { status: Constant.EQUIPMENT_STATUS_CODE_PENDING, }; - return Api.addEquipment(equipment).then((savedEquipment) => { + return this.props.dispatch(Api.addEquipment(equipment)).then((savedEquipment) => { this.setState({ isSaving: false }); this.props.onSave(savedEquipment); }); @@ -367,12 +366,12 @@ class EquipmentAddDialog extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - localAreas: state.lookups.localAreas, - districtEquipmentTypes: state.lookups.districtEquipmentTypes, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + localAreas: state.lookups.localAreas, + districtEquipmentTypes: state.lookups.districtEquipmentTypes, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(EquipmentAddDialog); +export default connect(mapStateToProps, mapDispatchToProps)(EquipmentAddDialog); diff --git a/client/src/js/views/dialogs/EquipmentChangeStatusDialog.jsx b/client/src/js/views/dialogs/EquipmentChangeStatusDialog.jsx index c07b29cc6..7f2067598 100644 --- a/client/src/js/views/dialogs/EquipmentChangeStatusDialog.jsx +++ b/client/src/js/views/dialogs/EquipmentChangeStatusDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { FormGroup, FormLabel, FormText } from 'react-bootstrap'; import * as Api from '../../api'; @@ -49,28 +50,28 @@ class EquipmentChangeStatusDialog extends React.Component { return valid; }; - formSubmitted = () => { + formSubmitted = async () => { if (this.isValid()) { this.setState({ isSaving: true }); + const dispatch = this.props.dispatch; const status = { id: this.props.equipment.id, status: this.props.status, statusComment: this.state.comment, }; - Api.changeEquipmentStatus(status) - .then(() => { - this.setState({ isSaving: false }); - this.props.onStatusChanged(); - Log.equipmentStatusModified(this.props.equipment, status.status, status.statusComment); - }) - .catch((error) => { - if (error.status === 400 && (error.errorCode === 'HETS-39' || error.errorCode === 'HETS-41')) { - this.setState({ commentError: error.errorDescription }); - } else { - throw error; - } - }); + try { + await dispatch(Api.changeEquipmentStatus(status)); + this.setState({ isSaving: false }); + this.props.onStatusChanged(); + await dispatch(Log.equipmentStatusModified(this.props.equipment, status.status, status.statusComment)); + } catch (error) { + if (error.status === 400 && (error.errorCode === 'HETS-39' || error.errorCode === 'HETS-41')) { + this.setState({ commentError: error.errorDescription }); + } else { + throw error; + } + } } }; @@ -103,4 +104,6 @@ class EquipmentChangeStatusDialog extends React.Component { } } -export default EquipmentChangeStatusDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(EquipmentChangeStatusDialog); diff --git a/client/src/js/views/dialogs/EquipmentEditDialog.jsx b/client/src/js/views/dialogs/EquipmentEditDialog.jsx index 7a73c0db0..828220d62 100644 --- a/client/src/js/views/dialogs/EquipmentEditDialog.jsx +++ b/client/src/js/views/dialogs/EquipmentEditDialog.jsx @@ -62,7 +62,7 @@ class EquipmentEditDialog extends React.Component { } componentDidMount() { - Api.getDistrictEquipmentTypes(); + this.props.dispatch(Api.getDistrictEquipmentTypes()); } componentDidUpdate(prevProps, prevState) { @@ -162,7 +162,7 @@ class EquipmentEditDialog extends React.Component { return valid; }; - formSubmitted = () => { + formSubmitted = async () => { if (this.isValid()) { if (this.didChange()) { if (this.state.duplicateSerialNumberWarning) { @@ -171,37 +171,37 @@ class EquipmentEditDialog extends React.Component { return this.saveEquipment(); } - return Api.equipmentDuplicateCheck(this.props.equipment.id, this.state.serialNumber).then((response) => { - if (response.data.length > 0) { - const equipmentCodes = response.data.map((district) => { - return district.duplicateEquipment.equipmentCode; - }); - var districts = _.chain(response.data) - .map((district) => district.districtName) - .uniq() - .value(); - const districtsPlural = districts.length === 1 ? 'district' : 'districts'; - this.setState({ - serialNumberError: `Serial number is currently in use for the equipment ${equipmentCodes.join( - ', ' - )}, in the following ${districtsPlural}: ${districts.join(', ')}`, - duplicateSerialNumberWarning: true, - }); - return null; - } else { - this.setState({ duplicateSerialNumberWarning: false }); - return this.saveEquipment(); - } - }); + const response = await this.props.dispatch(Api.equipmentDuplicateCheck(this.props.equipment.id, this.state.serialNumber)); + if (response.data.length > 0) { + const equipmentCodes = response.data.map((district) => { + return district.duplicateEquipment.equipmentCode; + }); + let districts = _.chain(response.data) + .map((district) => district.districtName) + .uniq() + .value(); + const districtsPlural = districts.length === 1 ? 'district' : 'districts'; + this.setState({ + serialNumberError: `Serial number is currently in use for the equipment ${equipmentCodes.join( + ', ' + )}, in the following ${districtsPlural}: ${districts.join(', ')}`, + duplicateSerialNumberWarning: true, + }); + return null; + } else { + this.setState({ duplicateSerialNumberWarning: false }); + return this.saveEquipment(); + } } else { this.props.onClose(); } } }; - saveEquipment = () => { + saveEquipment = async () => { this.setState({ isSaving: true }); + const dispatch = this.props.dispatch; const equipment = { ...this.props.equipment, localArea: { id: this.state.localAreaId }, @@ -218,16 +218,13 @@ class EquipmentEditDialog extends React.Component { pupLegalCapacity: this.state.pupLegalCapacity, }; - const promise = Api.updateEquipment(equipment); - - promise.then(() => { - Log.equipmentModified(this.props.equipment); - this.setState({ isSaving: false }); - if (this.props.onSave) { - this.props.onSave(); - } - this.props.onClose(); - }); + await dispatch(Api.updateEquipment(equipment)); + await dispatch(Log.equipmentModified(this.props.equipment)); + this.setState({ isSaving: false }); + if (this.props.onSave) { + this.props.onSave(); + } + this.props.onClose(); }; onLocalAreaChanged() { @@ -455,12 +452,12 @@ class EquipmentEditDialog extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - localAreas: state.lookups.localAreas, - districtEquipmentTypes: state.lookups.districtEquipmentTypes, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + localAreas: state.lookups.localAreas, + districtEquipmentTypes: state.lookups.districtEquipmentTypes, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(EquipmentEditDialog); +export default connect(mapStateToProps, mapDispatchToProps)(EquipmentEditDialog); diff --git a/client/src/js/views/dialogs/EquipmentRentalRatesEditDialog.jsx b/client/src/js/views/dialogs/EquipmentRentalRatesEditDialog.jsx index 904443018..a78a109f5 100644 --- a/client/src/js/views/dialogs/EquipmentRentalRatesEditDialog.jsx +++ b/client/src/js/views/dialogs/EquipmentRentalRatesEditDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { Container, Row, Col } from 'react-bootstrap'; import { FormGroup, FormText, FormLabel } from 'react-bootstrap'; @@ -85,7 +86,7 @@ class EquipmentRentalRatesEditDialog extends React.Component { rateComment: this.state.rateComment, }; - Api.updateRentalAgreement(rentalAgreement).then(() => { + this.props.dispatch(Api.updateRentalAgreement(rentalAgreement)).then(() => { if (this.props.onSave) { this.props.onSave(); } @@ -167,4 +168,6 @@ class EquipmentRentalRatesEditDialog extends React.Component { } } -export default EquipmentRentalRatesEditDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(EquipmentRentalRatesEditDialog); diff --git a/client/src/js/views/dialogs/EquipmentTransferDialog.jsx b/client/src/js/views/dialogs/EquipmentTransferDialog.jsx index ca06ea78b..5e8ae0bd8 100644 --- a/client/src/js/views/dialogs/EquipmentTransferDialog.jsx +++ b/client/src/js/views/dialogs/EquipmentTransferDialog.jsx @@ -55,7 +55,7 @@ class EquipmentTransferDialog extends React.Component { } componentDidMount() { - Api.getOwnersLite(); + this.props.dispatch(Api.getOwnersLite()); } updateState = (state, callback) => { @@ -324,7 +324,7 @@ class EquipmentTransferDialog extends React.Component { transferFunc = function () { if (this.validateSelectOwner()) { var ownerId = this.getOwner(this.state.donorOwnerCode).id; - Api.getOwnerEquipment(ownerId); + this.props.dispatch(Api.getOwnerEquipment(ownerId)); this.setState({ stage: STAGE_SELECT_EQUIPMENT }); } @@ -354,7 +354,7 @@ class EquipmentTransferDialog extends React.Component { var equipment = _.filter(this.props.equipment.data, (x) => _.includes(this.state.selectedEquipmentIds, x.id)); var includeSeniority = this.state.seniorityOption === OPTION_EQUIPMENT_AND_SENIORITY.id; - Api.transferEquipment(donorOwnerId, recipientOwnerId, equipment, includeSeniority) + this.props.dispatch(Api.transferEquipment(donorOwnerId, recipientOwnerId, equipment, includeSeniority)) .catch((error) => { if ( error.status === 400 && @@ -415,11 +415,11 @@ class EquipmentTransferDialog extends React.Component { } } -function mapStateToProps(state) { - return { - equipment: state.models.ownerEquipment, - owners: state.lookups.owners.lite, - }; -} +const mapStateToProps = (state) => ({ + equipment: state.models.ownerEquipment, + owners: state.lookups.owners.lite, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(EquipmentTransferDialog); +export default connect(mapStateToProps, mapDispatchToProps)(EquipmentTransferDialog); diff --git a/client/src/js/views/dialogs/HireOfferEditDialog.jsx b/client/src/js/views/dialogs/HireOfferEditDialog.jsx index f33d6cb2d..5591b5218 100644 --- a/client/src/js/views/dialogs/HireOfferEditDialog.jsx +++ b/client/src/js/views/dialogs/HireOfferEditDialog.jsx @@ -198,12 +198,9 @@ class HireOfferEditDialog extends React.Component { }; saveHireOffer = () => { - var promise = Promise.resolve(); - - if (this.state.equipmentVerifiedActive) { - // Update Equipment's last verified date - promise = Api.verifyEquipmentActive(this.props.hireOffer.equipment.id); - } + const dispatch = this.props.dispatch; + const promise = this.state.equipmentVerifiedActive ? + dispatch(Api.verifyEquipmentActive(this.props.hireOffer.equipment.id)) : Promise.resolve(); promise.then(() => { const hireOffer = { @@ -219,7 +216,7 @@ class HireOfferEditDialog extends React.Component { note: this.state.note, }; - Api.updateRentalRequestRotationList(hireOffer, this.props.rentalRequest).then(() => { + dispatch(Api.updateRentalRequestRotationList(hireOffer, this.props.rentalRequest)).then(() => { this.setState({ isSaving: false }); if (this.props.onSave) { this.props.onSave(hireOffer); @@ -401,8 +398,7 @@ class HireOfferEditDialog extends React.Component { } } -function mapStateToProps() { - return {}; -} +const mapStateToProps = () => ({}); +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(HireOfferEditDialog); +export default connect(mapStateToProps, mapDispatchToProps)(HireOfferEditDialog); diff --git a/client/src/js/views/dialogs/NotesDialog.jsx b/client/src/js/views/dialogs/NotesDialog.jsx index 7d52fe52e..c5b5d348f 100644 --- a/client/src/js/views/dialogs/NotesDialog.jsx +++ b/client/src/js/views/dialogs/NotesDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { ButtonGroup, Button, Alert } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import _ from 'lodash'; @@ -48,37 +49,34 @@ class NotesDialog extends React.Component { }); }; - onNoteAdded = (note) => { - this.props.saveNote(this.props.id, note).then((response) => { - this.props.getNotes(this.props.id); - this.setState({ notes: response }); - }); + onNoteAdded = async (note) => { + const response = await this.props.saveNote(this.props.id, note); + this.props.getNotes(this.props.id); + this.setState({ notes: response }); this.closeNotesAddDialog(); }; - onNoteUpdated = (note) => { + onNoteUpdated = async (note) => { const noteId = note.id; const updatedNotes = this.state.notes.map((_note) => { return _note.id === noteId ? { ..._note, ...note } : _note; }); this.setState({ notes: updatedNotes }); - Api.updateNote(note).then(() => { - this.props.getNotes(this.props.id); - }); + await this.props.dispatch(Api.updateNote(note)); + this.props.getNotes(this.props.id); this.closeNotesAddDialog(); }; - deleteNote = (note) => { + deleteNote = async (note) => { const noteId = note.id; const updatedNotes = this.state.notes.filter((note) => { return note.id !== noteId; }); this.setState({ notes: updatedNotes }); - Api.deleteNote(note.id).then(() => { - this.props.getNotes(this.props.id); - }); + await this.props.dispatch(Api.deleteNote(note.id)); + this.props.getNotes(this.props.id); }; editNote = (note) => { @@ -94,7 +92,7 @@ class NotesDialog extends React.Component { render() { const notes = _.orderBy(this.state.notes, ['createDate'], ['desc']); - var headers = [{ field: 'date', title: 'Date' }, { field: 'note', title: 'Note' }, { field: 'blank' }]; + const headers = [{ field: 'date', title: 'Date' }, { field: 'note', title: 'Note' }, { field: 'blank' }]; const showNoNotesMessage = !notes || notes.length === 0; @@ -139,4 +137,6 @@ class NotesDialog extends React.Component { } } -export default NotesDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(NotesDialog); diff --git a/client/src/js/views/dialogs/OvertimeRateEditDialog.jsx b/client/src/js/views/dialogs/OvertimeRateEditDialog.jsx index 3b793910c..7d3432b75 100644 --- a/client/src/js/views/dialogs/OvertimeRateEditDialog.jsx +++ b/client/src/js/views/dialogs/OvertimeRateEditDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { FormGroup, FormText, FormLabel, Row, Col } from 'react-bootstrap'; @@ -77,12 +78,12 @@ class OvertimeRateEditDialog extends React.Component { return valid; }; - formSubmitted = () => { + formSubmitted = async () => { if (this.isValid()) { if (this.didChange()) { this.setState({ isSaving: true }); - var rateType = { + const rateType = { id: this.state.rateId, rateType: this.state.rateType, description: this.state.description, @@ -92,15 +93,12 @@ class OvertimeRateEditDialog extends React.Component { active: true, }; - const promise = Api.updateOvertimeRateType(rateType); - - promise.then(() => { - this.setState({ isSaving: false }); - if (this.props.onSave) { - this.props.onSave(); - } - this.props.onClose(); - }); + await this.props.dispatch(Api.updateOvertimeRateType(rateType)); + this.setState({ isSaving: false }); + if (this.props.onSave) { + this.props.onSave(); + } + this.props.onClose(); } else { this.props.onClose(); } @@ -157,4 +155,6 @@ class OvertimeRateEditDialog extends React.Component { } } -export default OvertimeRateEditDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(OvertimeRateEditDialog); diff --git a/client/src/js/views/dialogs/OwnerChangeStatusDialog.jsx b/client/src/js/views/dialogs/OwnerChangeStatusDialog.jsx index b23e64220..06124d3d1 100644 --- a/client/src/js/views/dialogs/OwnerChangeStatusDialog.jsx +++ b/client/src/js/views/dialogs/OwnerChangeStatusDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { FormGroup, FormLabel, FormText } from 'react-bootstrap'; import _ from 'lodash'; @@ -85,7 +86,9 @@ class ChangeStatusDialog extends React.Component { return requirements; }; - formSubmitted = () => { + formSubmitted = async () => { + const dispatch = this.props.dispatch; + if (this.isValid()) { this.setState({ isSaving: true }); const status = { @@ -93,36 +96,37 @@ class ChangeStatusDialog extends React.Component { status: this.props.status, statusComment: this.state.comment, }; - var currentStatus = this.props.owner.status; - var equipmentList = { ...this.props.owner.equipmentList }; - - return Api.changeOwnerStatus(status) - .then(() => { - this.setState({ isSaving: false }); - this.props.onStatusChanged(status); - Log.ownerModifiedStatus(this.props.owner, status.status, status.statusComment); - // If owner status goes from approved to unapproved/archived or unapproved to archived - // this will change all it's equipment statuses. This should be reflected in the equipment history. - if ( - (currentStatus === Constant.OWNER_STATUS_CODE_APPROVED || - currentStatus === Constant.OWNER_STATUS_CODE_PENDING) && - (status.status === Constant.OWNER_STATUS_CODE_PENDING || - status.status === Constant.OWNER_STATUS_CODE_ARCHIVED) - ) { - _.map(equipmentList, (equipment) => { - if (equipment.status !== status.status) { - Log.equipmentStatusModified(equipment, status.status, status.statusComment); - } - }); - } - }) - .catch((error) => { - if (error.status === 400 && error.errorCode === 'HETS-40') { - this.setState({ commentError: error.errorDescription }); - } else { - throw error; - } - }); + const currentStatus = this.props.owner.status; + let equipmentList = { ...this.props.owner.equipmentList }; + + try { + await dispatch(Api.changeOwnerStatus(status)); + this.setState({ isSaving: false }); + this.props.onStatusChanged(status); + + await dispatch(Log.ownerModifiedStatus(this.props.owner, status.status, status.statusComment)); + + // If owner status goes from approved to unapproved/archived or unapproved to archived + // this will change all it's equipment statuses. This should be reflected in the equipment history. + if ( + (currentStatus === Constant.OWNER_STATUS_CODE_APPROVED || + currentStatus === Constant.OWNER_STATUS_CODE_PENDING) && + (status.status === Constant.OWNER_STATUS_CODE_PENDING || + status.status === Constant.OWNER_STATUS_CODE_ARCHIVED) + ) { + _.map(equipmentList, async (equipment) => { + if (equipment.status !== status.status) { + await dispatch(Log.equipmentStatusModified(equipment, status.status, status.statusComment)); + } + }); + } + } catch (error) { + if (error.status === 400 && error.errorCode === 'HETS-40') { + this.setState({ commentError: error.errorDescription }); + } else { + throw error; + } + } } }; @@ -175,4 +179,6 @@ class ChangeStatusDialog extends React.Component { } } -export default ChangeStatusDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(ChangeStatusDialog); diff --git a/client/src/js/views/dialogs/OwnersAddDialog.jsx b/client/src/js/views/dialogs/OwnersAddDialog.jsx index 6732d60fb..70818c650 100644 --- a/client/src/js/views/dialogs/OwnersAddDialog.jsx +++ b/client/src/js/views/dialogs/OwnersAddDialog.jsx @@ -75,7 +75,7 @@ class OwnersAddDialog extends React.Component { } componentDidMount() { - Api.getOwnersLite(); + this.props.dispatch(Api.getOwnersLite()); } updateState = (state, callback) => { @@ -260,11 +260,13 @@ class OwnersAddDialog extends React.Component { }; formSubmitted = () => { + const dispatch = this.props.dispatch; + if (this.isValid()) { if (this.didChange()) { this.setState({ isSaving: true }); - var owner = { + const owner = { organizationName: this.state.name, doingBusinessAs: this.state.doingBusinessAs, givenName: this.state.givenName, @@ -287,15 +289,14 @@ class OwnersAddDialog extends React.Component { status: this.state.status, }; - const promise = Api.addOwner(owner); - - promise.then((newOwner) => { - Log.ownerAdded(newOwner); - this.setState({ isSaving: false }); - if (this.props.onSave) { - this.props.onSave(newOwner); - } - this.props.onClose(); + dispatch(Api.addOwner(owner)).then((newOwner) => { + dispatch(Log.ownerAdded(newOwner)).then(() => { + this.setState({ isSaving: false }); + if (this.props.onSave) { + this.props.onSave(newOwner); + } + this.props.onClose(); + }); }); } else { this.props.onClose(); @@ -522,12 +523,12 @@ class OwnersAddDialog extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - owners: state.lookups.owners.lite, - localAreas: state.lookups.localAreas, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + owners: state.lookups.owners.lite, + localAreas: state.lookups.localAreas, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(OwnersAddDialog); +export default connect(mapStateToProps, mapDispatchToProps)(OwnersAddDialog); diff --git a/client/src/js/views/dialogs/OwnersEditDialog.jsx b/client/src/js/views/dialogs/OwnersEditDialog.jsx index 2f164c9af..01c081a9e 100644 --- a/client/src/js/views/dialogs/OwnersEditDialog.jsx +++ b/client/src/js/views/dialogs/OwnersEditDialog.jsx @@ -55,7 +55,7 @@ class OwnersEditDialog extends React.Component { } componentDidMount() { - Api.getOwnersLite(); + this.props.dispatch(Api.getOwnersLite()); } updateState = (state, callback) => { @@ -181,7 +181,7 @@ class OwnersEditDialog extends React.Component { status: this.state.status, }; - Api.updateOwner(owner).then(() => { + this.props.dispatch(Api.updateOwner(owner)).then(() => { if (this.props.onSave) { this.props.onSave(); } @@ -333,11 +333,11 @@ class OwnersEditDialog extends React.Component { } } -function mapStateToProps(state) { - return { - owners: state.lookups.owners.lite, - localAreas: state.lookups.localAreas, - }; -} +const mapStateToProps = (state) => ({ + owners: state.lookups.owners.lite, + localAreas: state.lookups.localAreas, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(OwnersEditDialog); +export default connect(mapStateToProps, mapDispatchToProps)(OwnersEditDialog); diff --git a/client/src/js/views/dialogs/OwnersPolicyEditDialog.jsx b/client/src/js/views/dialogs/OwnersPolicyEditDialog.jsx index 5cec3e55f..056c43b88 100644 --- a/client/src/js/views/dialogs/OwnersPolicyEditDialog.jsx +++ b/client/src/js/views/dialogs/OwnersPolicyEditDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { FormGroup, FormLabel, FormText, Row, Col } from 'react-bootstrap'; import * as Constant from '../../constants'; @@ -103,7 +104,7 @@ class OwnersPolicyEditDialog extends React.Component { cglEndDate: toZuluTime(this.state.cglEndDate), }; - Api.updateOwner(owner).then(() => { + this.props.dispatch(Api.updateOwner(owner)).then(() => { if (this.props.onSave) { this.props.onSave(); } @@ -190,4 +191,6 @@ class OwnersPolicyEditDialog extends React.Component { } } -export default OwnersPolicyEditDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(OwnersPolicyEditDialog); diff --git a/client/src/js/views/dialogs/ProjectsAddDialog.jsx b/client/src/js/views/dialogs/ProjectsAddDialog.jsx index aff407c64..72c2dbdfc 100644 --- a/client/src/js/views/dialogs/ProjectsAddDialog.jsx +++ b/client/src/js/views/dialogs/ProjectsAddDialog.jsx @@ -48,7 +48,7 @@ class ProjectsAddDialog extends React.Component { } componentDidMount() { - Api.getProjects(); + this.props.dispatch(Api.getProjects()); } updateState = (state, callback) => { @@ -120,12 +120,13 @@ class ProjectsAddDialog extends React.Component { return valid; }; - formSubmitted = () => { + formSubmitted = async () => { + const dispatch = this.props.dispatch; if (this.isValid()) { if (this.didChange()) { this.setState({ isSaving: true }); - var project = { + const project = { name: this.state.name, fiscalYear: this.state.fiscalYear, provincialProjectNumber: this.state.provincialProjectNumber, @@ -141,16 +142,13 @@ class ProjectsAddDialog extends React.Component { information: this.state.information, }; - const promise = Api.addProject(project); - - promise.then((newProject) => { - Log.projectAdded(newProject); - this.setState({ isSaving: false }); - if (this.props.onSave) { - this.props.onSave(newProject); - } - this.props.onClose(); - }); + const newProject = await dispatch(Api.addProject(project)); + dispatch(Log.projectAdded(newProject)); + this.setState({ isSaving: false }); + if (this.props.onSave) { + this.props.onSave(newProject); + } + this.props.onClose(); } else { this.props.onClose(); } @@ -293,12 +291,12 @@ class ProjectsAddDialog extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - projects: state.lookups.projects, - fiscalYears: state.lookups.fiscalYears, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + projects: state.lookups.projects, + fiscalYears: state.lookups.fiscalYears, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(ProjectsAddDialog); +export default connect(mapStateToProps, mapDispatchToProps)(ProjectsAddDialog); diff --git a/client/src/js/views/dialogs/ProjectsEditDialog.jsx b/client/src/js/views/dialogs/ProjectsEditDialog.jsx index a2b5ba628..b12cd7b7e 100644 --- a/client/src/js/views/dialogs/ProjectsEditDialog.jsx +++ b/client/src/js/views/dialogs/ProjectsEditDialog.jsx @@ -10,7 +10,6 @@ import _ from 'lodash'; import * as Action from '../../actionTypes'; import * as Api from '../../api'; import * as Log from '../../history'; -import store from '../../store'; import DropdownControl from '../../components/DropdownControl.jsx'; import FormDialog from '../../components/FormDialog.jsx'; @@ -51,7 +50,7 @@ class ProjectsEditDialog extends React.Component { } componentDidMount() { - Api.getProjects(); + this.props.dispatch(Api.getProjects()); } updateState = (state, callback) => { @@ -147,9 +146,10 @@ class ProjectsEditDialog extends React.Component { return valid; }; - formSubmitted = () => { + formSubmitted = async () => { if (this.isValid()) { if (this.didChange()) { + const dispatch = this.props.dispatch; const project = { ...this.props.project, id: this.props.project.id, @@ -168,11 +168,9 @@ class ProjectsEditDialog extends React.Component { concurrencyControlNumber: this.state.concurrencyControlNumber, }; - store.dispatch({ type: Action.UPDATE_PROJECT, project }); - - Log.projectModified(this.props.project); - - Api.updateProject(project); + dispatch({ type: Action.UPDATE_PROJECT, project }); + await dispatch(Log.projectModified(this.props.project)); + await dispatch(Api.updateProject(project)); } this.props.onClose(); @@ -309,11 +307,11 @@ class ProjectsEditDialog extends React.Component { } } -function mapStateToProps(state) { - return { - fiscalYears: state.lookups.fiscalYears, - projects: state.lookups.projects, - }; -} +const mapStateToProps = (state) => ({ + fiscalYears: state.lookups.fiscalYears, + projects: state.lookups.projects, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(ProjectsEditDialog); +export default connect(mapStateToProps, mapDispatchToProps)(ProjectsEditDialog); diff --git a/client/src/js/views/dialogs/RentalAgreementOvertimeNotesDialog.jsx b/client/src/js/views/dialogs/RentalAgreementOvertimeNotesDialog.jsx index ceac59c7e..65f817f25 100644 --- a/client/src/js/views/dialogs/RentalAgreementOvertimeNotesDialog.jsx +++ b/client/src/js/views/dialogs/RentalAgreementOvertimeNotesDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { Container, Row, Col, FormGroup, FormLabel } from 'react-bootstrap'; import _ from 'lodash'; @@ -42,7 +43,7 @@ class RentalAgreementOvertimeNotesDialog extends React.Component { }; formSubmitted = () => { - const { onSave, onClose } = this.props; + const { onSave, onClose, dispatch } = this.props; if (this.isValid()) { if (this.didChange()) { const rentalAgreement = { @@ -51,7 +52,7 @@ class RentalAgreementOvertimeNotesDialog extends React.Component { note: this.state.note, }; - Api.updateRentalAgreement(rentalAgreement).then(() => { + dispatch(Api.updateRentalAgreement(rentalAgreement)).then(() => { if (onSave) { onSave(); } @@ -117,4 +118,6 @@ class RentalAgreementOvertimeNotesDialog extends React.Component { } } -export default RentalAgreementOvertimeNotesDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(RentalAgreementOvertimeNotesDialog); diff --git a/client/src/js/views/dialogs/RentalAgreementsEditDialog.jsx b/client/src/js/views/dialogs/RentalAgreementsEditDialog.jsx index cef75ad6b..6713fcf8f 100644 --- a/client/src/js/views/dialogs/RentalAgreementsEditDialog.jsx +++ b/client/src/js/views/dialogs/RentalAgreementsEditDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { Row, Col } from 'react-bootstrap'; import { FormGroup, FormText, FormLabel } from 'react-bootstrap'; @@ -98,7 +99,7 @@ class RentalAgreementsEditDialog extends React.Component { agreementCity: this.state.agreementCity, }; - Api.updateRentalAgreement(rentalAgreement).then(() => { + this.props.dispatch(Api.updateRentalAgreement(rentalAgreement)).then(() => { if (this.props.onSave) { this.props.onSave(); } @@ -180,4 +181,6 @@ class RentalAgreementsEditDialog extends React.Component { } } -export default RentalAgreementsEditDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(RentalAgreementsEditDialog); diff --git a/client/src/js/views/dialogs/RentalConditionsEditDialog.jsx b/client/src/js/views/dialogs/RentalConditionsEditDialog.jsx index 5b59c90bf..b2e395319 100644 --- a/client/src/js/views/dialogs/RentalConditionsEditDialog.jsx +++ b/client/src/js/views/dialogs/RentalConditionsEditDialog.jsx @@ -44,7 +44,7 @@ class RentalConditionsEditDialog extends React.Component { } componentDidMount() { - Api.getRentalConditions(); + this.props.dispatch(Api.getRentalConditions()); } updateState = (value) => { @@ -94,7 +94,7 @@ class RentalConditionsEditDialog extends React.Component { }; formSubmitted = () => { - const { rentalAgreementId, onSave, onClose } = this.props; + const { rentalAgreementId, onSave, onClose, dispatch } = this.props; if (this.isValid()) { if (this.didChange()) { @@ -110,8 +110,8 @@ class RentalConditionsEditDialog extends React.Component { }); (this.state.isNew - ? Api.addRentalConditions(rentalAgreementId, conditions) - : Api.updateRentalCondition(_.first(conditions)) + ? dispatch(Api.addRentalConditions(rentalAgreementId, conditions)) + : dispatch(Api.updateRentalCondition(_.first(conditions))) ).then(() => { if (onSave) { onSave(); @@ -220,10 +220,10 @@ class RentalConditionsEditDialog extends React.Component { } } -function mapStateToProps(state) { - return { - rentalConditions: state.lookups.rentalConditions, - }; -} +const mapStateToProps = (state) => ({ + rentalConditions: state.lookups.rentalConditions, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(RentalConditionsEditDialog); +export default connect(mapStateToProps, mapDispatchToProps)(RentalConditionsEditDialog); diff --git a/client/src/js/views/dialogs/RentalRatesEditDialog.jsx b/client/src/js/views/dialogs/RentalRatesEditDialog.jsx index 4422d7268..201a1840c 100644 --- a/client/src/js/views/dialogs/RentalRatesEditDialog.jsx +++ b/client/src/js/views/dialogs/RentalRatesEditDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { Row, Col } from 'react-bootstrap'; import { FormGroup, FormText, FormLabel, Button } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -125,7 +126,7 @@ class RentalRatesEditDialog extends React.Component { }; formSubmitted = () => { - const { rentalAgreement, onSave, onClose } = this.props; + const { rentalAgreement, onSave, onClose, dispatch } = this.props; if (this.isValid()) { if (this.didChange()) { @@ -143,13 +144,14 @@ class RentalRatesEditDialog extends React.Component { }; }); - (this.state.isNew ? Api.addRentalRates(rentalAgreement.id, rates) : Api.updateRentalRate(_.first(rates))).then( - () => { - if (onSave) { - onSave(); - } - } - ); + (this.state.isNew ? + dispatch(Api.addRentalRates(rentalAgreement.id, rates)) : + dispatch(Api.updateRentalRate(_.first(rates)))) + .then(() => { + if (onSave) { + onSave(); + } + }); } onClose(); @@ -283,4 +285,6 @@ class RentalRatesEditDialog extends React.Component { } } -export default RentalRatesEditDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(RentalRatesEditDialog); diff --git a/client/src/js/views/dialogs/RentalRequestsAddDialog.jsx b/client/src/js/views/dialogs/RentalRequestsAddDialog.jsx index 946d9631e..03dddb31f 100644 --- a/client/src/js/views/dialogs/RentalRequestsAddDialog.jsx +++ b/client/src/js/views/dialogs/RentalRequestsAddDialog.jsx @@ -55,9 +55,9 @@ class RentalRequestsAddDialog extends React.Component { } componentDidMount() { - Api.getDistrictEquipmentTypes(); + this.props.dispatch(Api.getDistrictEquipmentTypes()); if (this.canChangeProject()) { - Api.getProjectsCurrentFiscal(); + this.props.dispatch(Api.getProjectsCurrentFiscal()); } } @@ -178,14 +178,15 @@ class RentalRequestsAddDialog extends React.Component { // TODO Restrict the available local areas to a project service area }; - formSubmitted = () => { + formSubmitted = async () => { if (this.isValid()) { if (this.didChange()) { this.setState({ isSaving: true }); + const dispatch = this.props.dispatch; const { rentalRequestAttachments } = this.state; - var request = { + const request = { project: { id: this.state.projectId }, localArea: { id: this.state.localAreaId }, districtEquipmentType: { id: this.state.equipmentTypeId }, @@ -202,21 +203,19 @@ class RentalRequestsAddDialog extends React.Component { ], }; - Api.addRentalRequest(request, this.props.viewOnly) - .then((response) => { - this.setState({ isSaving: false }); - - this.props.onRentalAdded(response); - this.props.onClose(); - }) - .catch((error) => { - this.setState({ isSaving: false }); - if (error.status === 400 && error.errorCode === 'HETS-28') { - this.setState({ savingError: error.errorDescription }); - } else { - throw error; - } - }); + try { + const response = await dispatch(Api.addRentalRequest(request, this.props.viewOnly)); + this.setState({ isSaving: false }); + this.props.onRentalAdded(response); + this.props.onClose(); + } catch (error) { + this.setState({ isSaving: false }); + if (error.status === 400 && error.errorCode === 'HETS-28') { + this.setState({ savingError: error.errorDescription }); + } else { + throw error; + } + } } } }; @@ -396,13 +395,13 @@ class RentalRequestsAddDialog extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - localAreas: state.lookups.localAreas, - districtEquipmentTypes: state.lookups.districtEquipmentTypes, - projects: state.lookups.projectsCurrentFiscal, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + localAreas: state.lookups.localAreas, + districtEquipmentTypes: state.lookups.districtEquipmentTypes, + projects: state.lookups.projectsCurrentFiscal, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(RentalRequestsAddDialog); +export default connect(mapStateToProps, mapDispatchToProps)(RentalRequestsAddDialog); diff --git a/client/src/js/views/dialogs/RentalRequestsEditDialog.jsx b/client/src/js/views/dialogs/RentalRequestsEditDialog.jsx index 707582f7d..7237602a1 100644 --- a/client/src/js/views/dialogs/RentalRequestsEditDialog.jsx +++ b/client/src/js/views/dialogs/RentalRequestsEditDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { FormGroup, FormText, FormLabel, FormControl } from 'react-bootstrap'; import Moment from 'moment'; @@ -116,7 +117,8 @@ class RentalRequestsEditDialog extends React.Component { return valid; }; - formSubmitted = () => { + formSubmitted = async () => { + const dispatch = this.props.dispatch; if (this.isValid()) { if (this.didChange()) { const rentalRequest = { @@ -133,12 +135,11 @@ class RentalRequestsEditDialog extends React.Component { ], }; - Api.updateRentalRequest(rentalRequest).then(() => { - Log.rentalRequestModified(this.props.rentalRequest); - if (this.props.onSave) { - this.props.onSave(); - } - }); + await dispatch(Api.updateRentalRequest(rentalRequest)); + await dispatch(Log.rentalRequestModified(this.props.rentalRequest)); + if (this.props.onSave) { + this.props.onSave(); + } } this.props.onClose(); @@ -235,4 +236,6 @@ class RentalRequestsEditDialog extends React.Component { } } -export default RentalRequestsEditDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(RentalRequestsEditDialog); diff --git a/client/src/js/views/dialogs/SeniorityEditDialog.jsx b/client/src/js/views/dialogs/SeniorityEditDialog.jsx index b458be179..dddaa7a7e 100644 --- a/client/src/js/views/dialogs/SeniorityEditDialog.jsx +++ b/client/src/js/views/dialogs/SeniorityEditDialog.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { Container, Row, Col } from 'react-bootstrap'; import { FormControl, FormGroup, FormText, FormLabel } from 'react-bootstrap'; @@ -138,11 +139,12 @@ class SeniorityEditDialog extends React.Component { this.setState({ isSeniorityOverridden: true }); }; - formSubmitted = () => { + formSubmitted = async () => { if (this.isValid()) { if (this.didChange()) { this.setState({ isSaving: true }); + const dispatch = this.props.dispatch; const equipment = { ...this.props.equipment, serviceHoursLastYear: (this.state.serviceHoursLastYear || 0).toFixed(2), @@ -154,16 +156,13 @@ class SeniorityEditDialog extends React.Component { seniorityOverrideReason: this.state.seniorityOverrideReason, }; - const promise = Api.updateEquipment(equipment); - - promise.then(() => { - Log.equipmentSeniorityModified(this.props.equipment); - this.setState({ isSaving: false }); - if (this.props.onSave) { - this.props.onSave(); - } - this.props.onClose(); - }); + await dispatch(Api.updateEquipment(equipment)); + await dispatch(Log.equipmentSeniorityModified(this.props.equipment)); + this.setState({ isSaving: false }); + if (this.props.onSave) { + this.props.onSave(); + } + this.props.onClose(); } else { this.props.onClose(); } @@ -294,4 +293,6 @@ class SeniorityEditDialog extends React.Component { } } -export default SeniorityEditDialog; +const mapDispatchToProps = (dispatch) => ({ dispatch }); + +export default connect(null, mapDispatchToProps)(SeniorityEditDialog); diff --git a/client/src/js/views/dialogs/TimeEntryDialog.jsx b/client/src/js/views/dialogs/TimeEntryDialog.jsx index e8b526837..f6883ec89 100644 --- a/client/src/js/views/dialogs/TimeEntryDialog.jsx +++ b/client/src/js/views/dialogs/TimeEntryDialog.jsx @@ -79,8 +79,8 @@ class TimeEntryDialog extends React.Component { componentDidMount() { if (this.state.selectingAgreement) { - Api.getProjectsCurrentFiscal(); - Api.getEquipmentLite(); + this.props.dispatch(Api.getProjectsCurrentFiscal()); + this.props.dispatch(Api.getEquipmentLite()); } else { this.setState({ loaded: false }); Promise.all([!this.props.project ? this.fetchProject(this.props.projectId) : null, this.fetchTimeRecords()]).then( @@ -92,11 +92,11 @@ class TimeEntryDialog extends React.Component { } fetchTimeRecords = () => { - return Api.getRentalAgreementTimeRecords(this.state.rentalAgreementId); + return this.props.dispatch(Api.getRentalAgreementTimeRecords(this.state.rentalAgreementId)); }; fetchProject = (projectId) => { - return Api.getProject(projectId).then((project) => { + return this.props.dispatch(Api.getProject(projectId)).then((project) => { this.setState({ projectFiscalYearStartDate: project.fiscalYearStartDate }); }); }; @@ -127,7 +127,7 @@ class TimeEntryDialog extends React.Component { if (this.validateSelectAgreement()) { this.setState({ isSaving: true }); - Api.getLatestRentalAgreement(this.state.equipmentId, this.state.projectId) + this.props.dispatch(Api.getLatestRentalAgreement(this.state.equipmentId, this.state.projectId)) .then((agreement) => { this.setState({ loaded: false, rentalAgreementId: agreement.id }); return Promise.all([this.fetchProject(this.state.projectId), this.fetchTimeRecords()]).then(() => { @@ -225,21 +225,20 @@ class TimeEntryDialog extends React.Component { if (this.didChange()) { this.setState({ isSaving: true }); - var timeEntry = { ...this.state.timeEntry }; + let timeEntry = { ...this.state.timeEntry }; Object.keys(timeEntry).forEach((key) => { timeEntry[key].hours = (timeEntry[key].hours || 0).toFixed(2); }); - const promise = Api.addRentalAgreementTimeRecords(this.state.rentalAgreementId, timeEntry); - - promise.then(() => { - this.setState({ isSaving: false }); - if (this.props.multipleEntryAllowed) { - this.resetStateToSelectAgreement(true); - } else { - this.props.onClose(); - } - }); + this.props.dispatch(Api.addRentalAgreementTimeRecords(this.state.rentalAgreementId, timeEntry)) + .then(() => { + this.setState({ isSaving: false }); + if (this.props.multipleEntryAllowed) { + this.resetStateToSelectAgreement(true); + } else { + this.props.onClose(); + } + }); } else { this.props.onClose(); } @@ -302,8 +301,9 @@ class TimeEntryDialog extends React.Component { }; deleteTimeRecord = (timeRecord) => { - Api.deleteTimeRecord(timeRecord.id).then(() => { - Api.getRentalAgreementTimeRecords(this.state.rentalAgreementId); + const dispatch = this.props.dispatch; + dispatch(Api.deleteTimeRecord(timeRecord.id)).then(() => { + dispatch(Api.getRentalAgreementTimeRecords(this.state.rentalAgreementId)); }); }; @@ -575,12 +575,12 @@ class TimeEntryDialog extends React.Component { }; } -function mapStateToProps(state) { - return { - rentalAgreementTimeRecords: state.models.rentalAgreementTimeRecords, - projects: state.lookups.projectsCurrentFiscal, - equipment: state.lookups.equipment.ts, - }; -} +const mapStateToProps = (state) => ({ + rentalAgreementTimeRecords: state.models.rentalAgreementTimeRecords, + projects: state.lookups.projectsCurrentFiscal, + equipment: state.lookups.equipment.ts, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(TimeEntryDialog); +export default connect(mapStateToProps, mapDispatchToProps)(TimeEntryDialog); diff --git a/client/src/js/views/dialogs/UserRoleAddDialog.jsx b/client/src/js/views/dialogs/UserRoleAddDialog.jsx index 1acea8dec..0ca672651 100644 --- a/client/src/js/views/dialogs/UserRoleAddDialog.jsx +++ b/client/src/js/views/dialogs/UserRoleAddDialog.jsx @@ -45,7 +45,7 @@ class UserRoleAddDialog extends React.Component { componentDidMount() { this.setState({ loading: true }); - Api.getRoles().then(() => { + this.props.dispatch(Api.getRoles()).then(() => { this.setState({ loading: false }); }); } @@ -108,7 +108,7 @@ class UserRoleAddDialog extends React.Component { expiryDate: toZuluTime(this.state.expiryDate), }; - Api.addUserRole(this.props.user.id, userRole).then(() => { + this.props.dispatch(Api.addUserRole(this.props.user.id, userRole)).then(() => { this.setState({ isSaving: false }); if (this.props.onSave) { this.props.onSave(); @@ -205,11 +205,11 @@ class UserRoleAddDialog extends React.Component { } } -function mapStateToProps(state) { - return { - currentUser: state.user, - roles: state.lookups.roles, - }; -} +const mapStateToProps = (state) => ({ + currentUser: state.user, + roles: state.lookups.roles, +}); + +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(UserRoleAddDialog); +export default connect(mapStateToProps, mapDispatchToProps)(UserRoleAddDialog); diff --git a/client/src/js/views/dialogs/UsersEditDialog.jsx b/client/src/js/views/dialogs/UsersEditDialog.jsx index 799a419ed..fc2070571 100644 --- a/client/src/js/views/dialogs/UsersEditDialog.jsx +++ b/client/src/js/views/dialogs/UsersEditDialog.jsx @@ -158,7 +158,7 @@ class UsersEditDialog extends React.Component { const isNewUser = this.state.isNew; const addOrUpdateUser = isNewUser ? Api.addUser : Api.updateUser; - addOrUpdateUser(user).then( + this.props.dispatch(addOrUpdateUser(user)).then( (userResponse) => { this.setState({ isSaving: false }); @@ -283,10 +283,7 @@ class UsersEditDialog extends React.Component { } } -function mapStateToProps(state) { - return { - districts: state.lookups.districts, - }; -} +const mapStateToProps = (state) => ({ districts: state.lookups.districts }); +const mapDispatchToProps = (dispatch) => ({ dispatch }); -export default connect(mapStateToProps)(UsersEditDialog); +export default connect(mapStateToProps, mapDispatchToProps)(UsersEditDialog); diff --git a/client/src/registerFaIcons.js b/client/src/registerFaIcons.js new file mode 100644 index 000000000..2a648012d --- /dev/null +++ b/client/src/registerFaIcons.js @@ -0,0 +1,73 @@ +import { library } from '@fortawesome/fontawesome-svg-core'; +import { + faCalendarAlt as faCalendarAltRegular, + faCheckCircle as faCheckCircleRegular, + faEdit as faEditRegular, + faFolderOpen as faFolderOpenRegular, + faStar as faStarRegular, + faTimesCircle as faTimesCircleRegular, + faTrashAlt as faTrashAltRegular, +} from '@fortawesome/free-regular-svg-icons'; + +import { + faArrowLeft, + faAsterisk, + faCalendarAlt, + faCheck, + faCheckCircle, + faCheckSquare, + faDownload, + faEdit, + faEnvelope, + faExclamationCircle, + faFolderOpen, + faFileUpload, + faMinus, + faPencilAlt, + faPlus, + faPrint, + faSortAmountDown, + faSortAmountDownAlt, + faStar, + faSyncAlt, + faTimes, + faTimesCircle, + faTrashAlt, + faUser, +} from '@fortawesome/free-solid-svg-icons'; + +export const registerFaIcons = () => { + library.add( + faCheckCircle, + faCheckCircleRegular, + faTimesCircle, + faTimesCircleRegular, + faCalendarAlt, + faCalendarAltRegular, + faTrashAlt, + faTrashAltRegular, + faEdit, + faEditRegular, + faPencilAlt, + faStar, + faStarRegular, + faTimes, + faFolderOpen, + faFolderOpenRegular, + faFileUpload, + faSyncAlt, + faPrint, + faArrowLeft, + faSortAmountDown, + faSortAmountDownAlt, + faPlus, + faCheck, + faCheckSquare, + faExclamationCircle, + faUser, + faAsterisk, + faEnvelope, + faMinus, + faDownload, + ); +}; diff --git a/client/src/setupTests.js b/client/src/setupTests.js index 8f2609b7b..567ac9b60 100644 --- a/client/src/setupTests.js +++ b/client/src/setupTests.js @@ -3,3 +3,6 @@ // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom import '@testing-library/jest-dom'; +import { registerFaIcons } from './registerFaIcons'; + +registerFaIcons(); diff --git a/openshift/api-build-config.yaml b/openshift/api-build-config.yaml index f78867b25..2109e43fb 100644 --- a/openshift/api-build-config.yaml +++ b/openshift/api-build-config.yaml @@ -9,7 +9,8 @@ objects: - apiVersion: image.openshift.io/v1 kind: ImageStream metadata: - name: dotnet-50-rhel8 + # name: dotnet-50-rhel8 + name: dotnet-70 labels: shared: "true" spec: @@ -19,8 +20,10 @@ objects: - annotations: null from: kind: DockerImage - name: registry.redhat.io/rhel8/dotnet-50:5.0-4 - name: "5.0" + # name: registry.redhat.io/rhel8/dotnet-50:5.0-4 + name: registry.redhat.io/rhel8/dotnet-70:7.0-18 + # name: "5.0" + name: "7.0" referencePolicy: type: Local - apiVersion: image.openshift.io/v1 @@ -82,7 +85,8 @@ objects: value: "${DOTNET_STARTUP_PROJECT}" from: kind: ImageStreamTag - name: "dotnet-50-rhel8:5.0" + # name: "dotnet-50-rhel8:5.0" + name: "dotnet-70:7.0" parameters: - description: Name of the project (HETS) displayName: PROJECT_NAME diff --git a/openshift/configmaps/api-appsettings.yaml b/openshift/configmaps/api-appsettings.yaml index 9d35a504d..5aab9b50e 100644 --- a/openshift/configmaps/api-appsettings.yaml +++ b/openshift/configmaps/api-appsettings.yaml @@ -21,8 +21,8 @@ objects: "LogoffUrl-Training": "https://logontest.gov.bc.ca/clp-cgi/logoff.cgi?returl=https://trn-hets.th.gov.bc.ca&retnow=1", "LogoffUrl-UAT": "https://logontest.gov.bc.ca/clp-cgi/logoff.cgi?returl=https://uat-hets.th.gov.bc.ca&retnow=1", "LogoffUrl-Production": "https://logon.gov.bc.ca/clp-cgi/logoff.cgi?returl=https://hets.th.gov.bc.ca&retnow=1", - "Version-Application": "Release 1.10.8.0", - "Version-Database": "Release 1.10.8.0", + "Version-Application": "Release 1.10.9.0", + "Version-Database": "Release 1.10.9.0", "Maximum-Blank-Agreements": "3", "ExceptionDescriptions": { "HETS-01": "Record not found", @@ -93,7 +93,7 @@ objects: "DumpTruck": 600 }, "ConnectionStrings": { - "HETS": "Host=localhost;Username=postgres;Password=postgres;Database=hets;Port=9000;" + "HETS": "Host=localhost;Username=postgres;Password=postgres;Database=hets;" }, "JWT": { "Authority": "https://dev.loginproxy.gov.bc.ca/auth/realms/",