From 3885756a51fc650e128898e9310275d3ad748c72 Mon Sep 17 00:00:00 2001 From: Shawn Jackson Date: Wed, 18 Mar 2026 15:38:46 -0700 Subject: [PATCH 1/2] RE1-T105 Fixing map issue --- .../Repositories/IRouteStopsRepository.cs | 1 + Core/Resgrid.Model/RouteStop.cs | 2 + Core/Resgrid.Model/Services/IRouteService.cs | 1 + Core/Resgrid.Services/RouteService.cs | 12 + .../M0054_AddContactIdToRouteStops.cs | 19 ++ .../M0054_AddContactIdToRouteStopsPg.cs | 19 ++ .../Configs/SqlConfiguration.cs | 1 + .../SelectRouteStopsByContactIdQuery.cs | 33 ++ .../RouteStopsRepository.cs | 36 ++ .../PostgreSql/PostgreSqlConfiguration.cs | 4 + .../SqlServer/SqlServerConfiguration.cs | 4 + .../User/Controllers/ContactsController.cs | 16 +- .../User/Controllers/IndoorMapsController.cs | 2 +- .../User/Controllers/RoutesController.cs | 67 +++- .../User/Models/Contacts/ViewContactView.cs | 2 + .../User/Models/Routes/RouteViewModels.cs | 24 ++ .../Areas/User/Views/Contacts/View.cshtml | 57 ++++ .../Areas/User/Views/IndoorMaps/Floors.cshtml | 4 +- .../Areas/User/Views/Routes/Edit.cshtml | 11 + .../Areas/User/Views/Routes/New.cshtml | 150 ++++++++ .../resgrid.dispatch.addArchivedCall.js | 20 +- .../dispatch/resgrid.dispatch.editcall.js | 20 +- .../dispatch/resgrid.dispatch.newcall.js | 24 +- .../internal/routes/resgrid.routes.edit.js | 47 ++- .../app/internal/routes/resgrid.routes.new.js | 323 +++++++++++++++++- 25 files changed, 871 insertions(+), 28 deletions(-) create mode 100644 Providers/Resgrid.Providers.Migrations/Migrations/M0054_AddContactIdToRouteStops.cs create mode 100644 Providers/Resgrid.Providers.MigrationsPg/Migrations/M0054_AddContactIdToRouteStopsPg.cs create mode 100644 Repositories/Resgrid.Repositories.DataRepository/Queries/Routes/SelectRouteStopsByContactIdQuery.cs diff --git a/Core/Resgrid.Model/Repositories/IRouteStopsRepository.cs b/Core/Resgrid.Model/Repositories/IRouteStopsRepository.cs index 36d87557a..255e37332 100644 --- a/Core/Resgrid.Model/Repositories/IRouteStopsRepository.cs +++ b/Core/Resgrid.Model/Repositories/IRouteStopsRepository.cs @@ -7,5 +7,6 @@ public interface IRouteStopsRepository : IRepository { Task> GetStopsByRoutePlanIdAsync(string routePlanId); Task> GetStopsByCallIdAsync(int callId); + Task> GetStopsByContactIdAsync(string contactId); } } diff --git a/Core/Resgrid.Model/RouteStop.cs b/Core/Resgrid.Model/RouteStop.cs index 22a893c1c..a796d4b9c 100644 --- a/Core/Resgrid.Model/RouteStop.cs +++ b/Core/Resgrid.Model/RouteStop.cs @@ -41,6 +41,8 @@ public class RouteStop : IEntity public string ContactNumber { get; set; } + public string ContactId { get; set; } + public string Notes { get; set; } public bool IsDeleted { get; set; } diff --git a/Core/Resgrid.Model/Services/IRouteService.cs b/Core/Resgrid.Model/Services/IRouteService.cs index 54b663399..8e3435e8f 100644 --- a/Core/Resgrid.Model/Services/IRouteService.cs +++ b/Core/Resgrid.Model/Services/IRouteService.cs @@ -17,6 +17,7 @@ public interface IRouteService // Route Stop CRUD Task SaveRouteStopAsync(RouteStop routeStop, CancellationToken cancellationToken = default); Task> GetRouteStopsForPlanAsync(string routePlanId); + Task> GetRouteStopsForContactAsync(string contactId, int departmentId); Task ReorderRouteStopsAsync(string routePlanId, List orderedStopIds, CancellationToken cancellationToken = default); Task DeleteRouteStopAsync(string routeStopId, CancellationToken cancellationToken = default); diff --git a/Core/Resgrid.Services/RouteService.cs b/Core/Resgrid.Services/RouteService.cs index 01c31063c..d00dd0686 100644 --- a/Core/Resgrid.Services/RouteService.cs +++ b/Core/Resgrid.Services/RouteService.cs @@ -84,6 +84,18 @@ public async Task> GetRouteStopsForPlanAsync(string routePlanId) return stops?.Where(x => !x.IsDeleted).OrderBy(x => x.StopOrder).ToList() ?? new List(); } + public async Task> GetRouteStopsForContactAsync(string contactId, int departmentId) + { + var stops = await _routeStopsRepository.GetStopsByContactIdAsync(contactId); + if (stops == null) + return new List(); + + var plans = await _routePlansRepository.GetRoutePlansByDepartmentIdAsync(departmentId); + var planIds = plans?.Where(p => !p.IsDeleted).Select(p => p.RoutePlanId).ToHashSet() ?? new HashSet(); + + return stops.Where(s => !s.IsDeleted && planIds.Contains(s.RoutePlanId)).ToList(); + } + public async Task ReorderRouteStopsAsync(string routePlanId, List orderedStopIds, CancellationToken cancellationToken = default) { var stops = await _routeStopsRepository.GetStopsByRoutePlanIdAsync(routePlanId); diff --git a/Providers/Resgrid.Providers.Migrations/Migrations/M0054_AddContactIdToRouteStops.cs b/Providers/Resgrid.Providers.Migrations/Migrations/M0054_AddContactIdToRouteStops.cs new file mode 100644 index 000000000..8575a431c --- /dev/null +++ b/Providers/Resgrid.Providers.Migrations/Migrations/M0054_AddContactIdToRouteStops.cs @@ -0,0 +1,19 @@ +using FluentMigrator; + +namespace Resgrid.Providers.Migrations.Migrations +{ + [Migration(54)] + public class M0054_AddContactIdToRouteStops : Migration + { + public override void Up() + { + Alter.Table("RouteStops") + .AddColumn("ContactId").AsString(128).Nullable(); + } + + public override void Down() + { + Delete.Column("ContactId").FromTable("RouteStops"); + } + } +} diff --git a/Providers/Resgrid.Providers.MigrationsPg/Migrations/M0054_AddContactIdToRouteStopsPg.cs b/Providers/Resgrid.Providers.MigrationsPg/Migrations/M0054_AddContactIdToRouteStopsPg.cs new file mode 100644 index 000000000..09967eb54 --- /dev/null +++ b/Providers/Resgrid.Providers.MigrationsPg/Migrations/M0054_AddContactIdToRouteStopsPg.cs @@ -0,0 +1,19 @@ +using FluentMigrator; + +namespace Resgrid.Providers.MigrationsPg.Migrations +{ + [Migration(54)] + public class M0054_AddContactIdToRouteStopsPg : Migration + { + public override void Up() + { + Alter.Table("routestops") + .AddColumn("contactid").AsCustom("citext").Nullable(); + } + + public override void Down() + { + Delete.Column("contactid").FromTable("routestops"); + } + } +} diff --git a/Repositories/Resgrid.Repositories.DataRepository/Configs/SqlConfiguration.cs b/Repositories/Resgrid.Repositories.DataRepository/Configs/SqlConfiguration.cs index 29df31574..49e071c10 100644 --- a/Repositories/Resgrid.Repositories.DataRepository/Configs/SqlConfiguration.cs +++ b/Repositories/Resgrid.Repositories.DataRepository/Configs/SqlConfiguration.cs @@ -497,6 +497,7 @@ protected SqlConfiguration() { } public string SelectActiveRoutePlansByDepartmentIdQuery { get; set; } public string SelectRouteStopsByRoutePlanIdQuery { get; set; } public string SelectRouteStopsByCallIdQuery { get; set; } + public string SelectRouteStopsByContactIdQuery { get; set; } public string SelectRouteSchedulesByRoutePlanIdQuery { get; set; } public string SelectActiveSchedulesDueQuery { get; set; } public string SelectRouteInstancesByDepartmentIdQuery { get; set; } diff --git a/Repositories/Resgrid.Repositories.DataRepository/Queries/Routes/SelectRouteStopsByContactIdQuery.cs b/Repositories/Resgrid.Repositories.DataRepository/Queries/Routes/SelectRouteStopsByContactIdQuery.cs new file mode 100644 index 000000000..281b4f150 --- /dev/null +++ b/Repositories/Resgrid.Repositories.DataRepository/Queries/Routes/SelectRouteStopsByContactIdQuery.cs @@ -0,0 +1,33 @@ +using Resgrid.Model; +using Resgrid.Model.Repositories.Queries.Contracts; +using Resgrid.Repositories.DataRepository.Configs; +using Resgrid.Repositories.DataRepository.Extensions; + +namespace Resgrid.Repositories.DataRepository.Queries.Routes +{ + public class SelectRouteStopsByContactIdQuery : ISelectQuery + { + private readonly SqlConfiguration _sqlConfiguration; + public SelectRouteStopsByContactIdQuery(SqlConfiguration sqlConfiguration) + { + _sqlConfiguration = sqlConfiguration; + } + + public string GetQuery() + { + var query = _sqlConfiguration.SelectRouteStopsByContactIdQuery + .ReplaceQueryParameters(_sqlConfiguration, _sqlConfiguration.SchemaName, + _sqlConfiguration.RouteStopsTableName, + _sqlConfiguration.ParameterNotation, + new string[] { "%CONTACTID%" }, + new string[] { "ContactId" }); + + return query; + } + + public string GetQuery() where TEntity : class, IEntity + { + throw new System.NotImplementedException(); + } + } +} diff --git a/Repositories/Resgrid.Repositories.DataRepository/RouteStopsRepository.cs b/Repositories/Resgrid.Repositories.DataRepository/RouteStopsRepository.cs index 42b0038ba..0166594a6 100644 --- a/Repositories/Resgrid.Repositories.DataRepository/RouteStopsRepository.cs +++ b/Repositories/Resgrid.Repositories.DataRepository/RouteStopsRepository.cs @@ -102,5 +102,41 @@ public async Task> GetStopsByCallIdAsync(int callId) throw; } } + + public async Task> GetStopsByContactIdAsync(string contactId) + { + try + { + var selectFunction = new Func>>(async x => + { + var dynamicParameters = new DynamicParametersExtension(); + dynamicParameters.Add("ContactId", contactId); + + var query = _queryFactory.GetQuery(); + + return await x.QueryAsync(sql: query, param: dynamicParameters, transaction: _unitOfWork.Transaction); + }); + + DbConnection conn = null; + if (_unitOfWork?.Connection == null) + { + using (conn = _connectionProvider.Create()) + { + await conn.OpenAsync(); + return await selectFunction(conn); + } + } + else + { + conn = _unitOfWork.CreateOrGetConnection(); + return await selectFunction(conn); + } + } + catch (Exception ex) + { + Logging.LogException(ex); + throw; + } + } } } diff --git a/Repositories/Resgrid.Repositories.DataRepository/Servers/PostgreSql/PostgreSqlConfiguration.cs b/Repositories/Resgrid.Repositories.DataRepository/Servers/PostgreSql/PostgreSqlConfiguration.cs index c8399371f..fbec52792 100644 --- a/Repositories/Resgrid.Repositories.DataRepository/Servers/PostgreSql/PostgreSqlConfiguration.cs +++ b/Repositories/Resgrid.Repositories.DataRepository/Servers/PostgreSql/PostgreSqlConfiguration.cs @@ -1515,6 +1515,10 @@ DELETE FROM %SCHEMA%.%TABLENAME% SELECT * FROM %SCHEMA%.%TABLENAME% WHERE CallId = %CALLID% AND IsDeleted = false"; + SelectRouteStopsByContactIdQuery = @" + SELECT * + FROM %SCHEMA%.%TABLENAME% + WHERE ContactId = %CONTACTID% AND IsDeleted = false"; SelectRouteSchedulesByRoutePlanIdQuery = @" SELECT * FROM %SCHEMA%.%TABLENAME% diff --git a/Repositories/Resgrid.Repositories.DataRepository/Servers/SqlServer/SqlServerConfiguration.cs b/Repositories/Resgrid.Repositories.DataRepository/Servers/SqlServer/SqlServerConfiguration.cs index 7e25ef0fc..f733589d2 100644 --- a/Repositories/Resgrid.Repositories.DataRepository/Servers/SqlServer/SqlServerConfiguration.cs +++ b/Repositories/Resgrid.Repositories.DataRepository/Servers/SqlServer/SqlServerConfiguration.cs @@ -1479,6 +1479,10 @@ DELETE FROM %SCHEMA%.%TABLENAME% SELECT * FROM %SCHEMA%.%TABLENAME% WHERE [CallId] = %CALLID% AND [IsDeleted] = 0"; + SelectRouteStopsByContactIdQuery = @" + SELECT * + FROM %SCHEMA%.%TABLENAME% + WHERE [ContactId] = %CONTACTID% AND [IsDeleted] = 0"; SelectRouteSchedulesByRoutePlanIdQuery = @" SELECT * FROM %SCHEMA%.%TABLENAME% diff --git a/Web/Resgrid.Web/Areas/User/Controllers/ContactsController.cs b/Web/Resgrid.Web/Areas/User/Controllers/ContactsController.cs index e74e54523..8f0691a37 100644 --- a/Web/Resgrid.Web/Areas/User/Controllers/ContactsController.cs +++ b/Web/Resgrid.Web/Areas/User/Controllers/ContactsController.cs @@ -37,11 +37,12 @@ public class ContactsController : SecureBaseController private readonly IUserDefinedFieldsService _userDefinedFieldsService; private readonly IUdfRenderingService _udfRenderingService; private readonly IDepartmentGroupsService _departmentGroupsService; + private readonly IRouteService _routeService; public ContactsController(IContactsService contactsService, IDepartmentsService departmentsService, IUserProfileService userProfileService, IAddressService addressService, IEventAggregator eventAggregator, ICallsService callsService, IAuthorizationService authorizationService, IUserDefinedFieldsService userDefinedFieldsService, IUdfRenderingService udfRenderingService, - IDepartmentGroupsService departmentGroupsService) + IDepartmentGroupsService departmentGroupsService, IRouteService routeService) { _contactsService = contactsService; _departmentsService = departmentsService; @@ -53,6 +54,7 @@ public ContactsController(IContactsService contactsService, IDepartmentsService _userDefinedFieldsService = userDefinedFieldsService; _udfRenderingService = udfRenderingService; _departmentGroupsService = departmentGroupsService; + _routeService = routeService; } #endregion Private Members and Constructors @@ -128,6 +130,18 @@ public async Task View(string contactId) model.Notes = await _contactsService.GetContactNotesByContactIdAsync(contactId, DepartmentId); + model.RouteStops = await _routeService.GetRouteStopsForContactAsync(contactId, DepartmentId); + if (model.RouteStops.Count > 0) + { + var planIds = model.RouteStops.Select(s => s.RoutePlanId).Distinct().ToList(); + var allPlans = await _routeService.GetRoutePlansForDepartmentAsync(DepartmentId); + model.RoutePlans = allPlans.Where(p => planIds.Contains(p.RoutePlanId)).ToList(); + } + else + { + model.RoutePlans = new List(); + } + var udfDefinition = await _userDefinedFieldsService.GetActiveDefinitionAsync(DepartmentId, (int)UdfEntityType.Contact); if (udfDefinition != null) { diff --git a/Web/Resgrid.Web/Areas/User/Controllers/IndoorMapsController.cs b/Web/Resgrid.Web/Areas/User/Controllers/IndoorMapsController.cs index b25e986d0..48ac1bbf6 100644 --- a/Web/Resgrid.Web/Areas/User/Controllers/IndoorMapsController.cs +++ b/Web/Resgrid.Web/Areas/User/Controllers/IndoorMapsController.cs @@ -27,7 +27,7 @@ public async Task SearchZones(string term) var zones = await _indoorMapService.SearchZonesAsync(DepartmentId, term); - var results = zones.Select(z => new + var results = (zones ?? Enumerable.Empty()).Select(z => new { id = z.IndoorMapZoneId, text = z.Name, diff --git a/Web/Resgrid.Web/Areas/User/Controllers/RoutesController.cs b/Web/Resgrid.Web/Areas/User/Controllers/RoutesController.cs index a7fc1c11a..6636e81a6 100644 --- a/Web/Resgrid.Web/Areas/User/Controllers/RoutesController.cs +++ b/Web/Resgrid.Web/Areas/User/Controllers/RoutesController.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -17,12 +18,14 @@ public class RoutesController : SecureBaseController private readonly IRouteService _routeService; private readonly IUnitsService _unitsService; private readonly ICallsService _callsService; + private readonly IContactsService _contactsService; - public RoutesController(IRouteService routeService, IUnitsService unitsService, ICallsService callsService) + public RoutesController(IRouteService routeService, IUnitsService unitsService, ICallsService callsService, IContactsService contactsService) { _routeService = routeService; _unitsService = unitsService; _callsService = callsService; + _contactsService = contactsService; } [HttpGet] @@ -40,6 +43,7 @@ public async Task New() { var model = new RouteNewView(); model.Units = (await _unitsService.GetUnitsForDepartmentAsync(DepartmentId)).ToList(); + model.Contacts = (await _contactsService.GetAllContactsForDepartmentAsync(DepartmentId)).ToList(); return View(model); } @@ -57,10 +61,51 @@ public async Task New(RouteNewView model, CancellationToken cance await _routeService.SaveRoutePlanAsync(model.Plan, cancellationToken); + if (!string.IsNullOrWhiteSpace(model.PendingStopsJson)) + { + var options = new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + var pendingStops = System.Text.Json.JsonSerializer.Deserialize>(model.PendingStopsJson, options); + if (pendingStops != null) + { + for (int i = 0; i < pendingStops.Count; i++) + { + var ps = pendingStops[i]; + var stop = new RouteStop + { + RoutePlanId = model.Plan.RoutePlanId, + Name = ps.Name, + Description = ps.Description, + StopType = ps.StopType, + Priority = ps.Priority, + Latitude = ps.Latitude, + Longitude = ps.Longitude, + Address = ps.Address, + CallId = ps.CallId, + EstimatedDwellMinutes = ps.DwellMinutes, + ContactName = ps.ContactName, + ContactNumber = ps.ContactNumber, + ContactId = ps.ContactId, + Notes = ps.Notes, + StopOrder = i + 1, + AddedOn = DateTime.UtcNow, + IsDeleted = false + }; + + if (!string.IsNullOrWhiteSpace(ps.PlannedArrival) && DateTime.TryParse(ps.PlannedArrival, out var arrivalDt)) + stop.PlannedArrivalTime = arrivalDt.ToUniversalTime(); + if (!string.IsNullOrWhiteSpace(ps.PlannedDeparture) && DateTime.TryParse(ps.PlannedDeparture, out var departureDt)) + stop.PlannedDepartureTime = departureDt.ToUniversalTime(); + + await _routeService.SaveRouteStopAsync(stop, cancellationToken); + } + } + } + return RedirectToAction("Index"); } model.Units = (await _unitsService.GetUnitsForDepartmentAsync(DepartmentId)).ToList(); + model.Contacts = (await _contactsService.GetAllContactsForDepartmentAsync(DepartmentId)).ToList(); return View(model); } @@ -77,6 +122,7 @@ public async Task Edit(string id) model.Stops = await _routeService.GetRouteStopsForPlanAsync(id); model.Schedules = await _routeService.GetSchedulesForPlanAsync(id); model.Units = (await _unitsService.GetUnitsForDepartmentAsync(DepartmentId)).ToList(); + model.Contacts = (await _contactsService.GetAllContactsForDepartmentAsync(DepartmentId)).ToList(); return View(model); } @@ -103,6 +149,7 @@ public async Task Edit(RouteEditView model, CancellationToken can } model.Units = (await _unitsService.GetUnitsForDepartmentAsync(DepartmentId)).ToList(); + model.Contacts = (await _contactsService.GetAllContactsForDepartmentAsync(DepartmentId)).ToList(); return View(model); } @@ -175,12 +222,26 @@ public async Task GetCallsForLinking() return Json(all); } + [HttpGet] + [Authorize(Policy = ResgridResources.Route_View)] + public async Task GetContactsForStop() + { + var contacts = await _contactsService.GetAllContactsForDepartmentAsync(DepartmentId); + var result = contacts.OrderBy(c => c.GetName()).Select(c => new + { + id = c.ContactId, + name = c.GetName(), + phone = c.CellPhoneNumber ?? c.OfficePhoneNumber ?? c.HomePhoneNumber ?? string.Empty + }).ToList(); + return Json(result); + } + [HttpPost] [ValidateAntiForgeryToken] [Authorize(Policy = ResgridResources.Route_Update)] public async Task AddStop(string routePlanId, string name, string description, int stopType, int priority, decimal latitude, decimal longitude, string address, int? callId, int? geofenceRadius, - string plannedArrival, string plannedDeparture, int? dwellMinutes, string contactName, string contactNumber, string notes, + string plannedArrival, string plannedDeparture, int? dwellMinutes, string contactName, string contactNumber, string contactId, string notes, CancellationToken cancellationToken) { var plan = await _routeService.GetRoutePlanByIdAsync(routePlanId); @@ -203,6 +264,7 @@ public async Task AddStop(string routePlanId, string name, string EstimatedDwellMinutes = dwellMinutes, ContactName = contactName, ContactNumber = contactNumber, + ContactId = contactId, Notes = notes, StopOrder = existingStops.Count + 1, AddedOn = DateTime.UtcNow, @@ -257,5 +319,6 @@ public async Task InstanceDetail(string instanceId) model.Stops = stops; return View(model); } + } } diff --git a/Web/Resgrid.Web/Areas/User/Models/Contacts/ViewContactView.cs b/Web/Resgrid.Web/Areas/User/Models/Contacts/ViewContactView.cs index 28eafd23a..b193f4e5b 100644 --- a/Web/Resgrid.Web/Areas/User/Models/Contacts/ViewContactView.cs +++ b/Web/Resgrid.Web/Areas/User/Models/Contacts/ViewContactView.cs @@ -12,5 +12,7 @@ public class ViewContactView public Address MailingAddress { get; set; } public List Notes { get; set; } public List NoteTypes { get; set; } + public List RouteStops { get; set; } + public List RoutePlans { get; set; } } } diff --git a/Web/Resgrid.Web/Areas/User/Models/Routes/RouteViewModels.cs b/Web/Resgrid.Web/Areas/User/Models/Routes/RouteViewModels.cs index 13f5f057c..b1923f7d9 100644 --- a/Web/Resgrid.Web/Areas/User/Models/Routes/RouteViewModels.cs +++ b/Web/Resgrid.Web/Areas/User/Models/Routes/RouteViewModels.cs @@ -13,25 +13,49 @@ public class RouteNewView : BaseUserModel { public RoutePlan Plan { get; set; } public List Units { get; set; } + public List Contacts { get; set; } + public string PendingStopsJson { get; set; } public RouteNewView() { Plan = new RoutePlan(); Units = new List(); + Contacts = new List(); } } + public class PendingStopDto + { + public string Name { get; set; } + public string Description { get; set; } + public int StopType { get; set; } + public int Priority { get; set; } + public decimal Latitude { get; set; } + public decimal Longitude { get; set; } + public string Address { get; set; } + public int? CallId { get; set; } + public string PlannedArrival { get; set; } + public string PlannedDeparture { get; set; } + public int? DwellMinutes { get; set; } + public string ContactName { get; set; } + public string ContactNumber { get; set; } + public string ContactId { get; set; } + public string Notes { get; set; } + } + public class RouteEditView : BaseUserModel { public RoutePlan Plan { get; set; } public List Stops { get; set; } public List Schedules { get; set; } public List Units { get; set; } + public List Contacts { get; set; } public RouteEditView() { Plan = new RoutePlan(); Stops = new List(); Schedules = new List(); Units = new List(); + Contacts = new List(); } } diff --git a/Web/Resgrid.Web/Areas/User/Views/Contacts/View.cshtml b/Web/Resgrid.Web/Areas/User/Views/Contacts/View.cshtml index b5c49b15c..c530d3040 100644 --- a/Web/Resgrid.Web/Areas/User/Views/Contacts/View.cshtml +++ b/Web/Resgrid.Web/Areas/User/Views/Contacts/View.cshtml @@ -1,5 +1,6 @@ @model Resgrid.Web.Areas.User.Models.Contacts.ViewContactView @inject IStringLocalizer localizer +@using System.Linq @{ ViewBag.Title = "Resgrid | " + @localizer["ViewContactHeader"]; } @@ -27,6 +28,14 @@ @localizer["Calls"] + @if (Model.RouteStops != null && Model.RouteStops.Count > 0) + { + + } @if (!string.IsNullOrEmpty(Model.UdfReadOnlyHtml)) { } @@ -464,11 +464,11 @@ - - - - - + + + + + @@ -487,10 +487,10 @@ diff --git a/Web/Resgrid.Web/Areas/User/Views/Routes/Edit.cshtml b/Web/Resgrid.Web/Areas/User/Views/Routes/Edit.cshtml index 5a3673732..d8db16f76 100644 --- a/Web/Resgrid.Web/Areas/User/Views/Routes/Edit.cshtml +++ b/Web/Resgrid.Web/Areas/User/Views/Routes/Edit.cshtml @@ -293,7 +293,7 @@ var osmTileAttribution = '@Resgrid.Config.MappingConfig.LeafletAttribution'; var editStops =@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Stops.OrderBy(s => s.StopOrder).Select(s => new { id = s.RouteStopId, s.Name, lat = s.Latitude, lng = s.Longitude }))); var routePlanId = '@Model.Plan.RoutePlanId'; - var availableContacts = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Contacts.Select(c => new { id = c.ContactId, name = c.GetName(), phone = c.CellPhoneNumber ?? c.OfficePhoneNumber ?? c.HomePhoneNumber ?? "" }))); + var availableContacts = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject((Model.Contacts ?? Enumerable.Empty()).Select(c => new { id = c.ContactId ?? "", name = c.GetName() ?? "", phone = c.CellPhoneNumber ?? c.OfficePhoneNumber ?? c.HomePhoneNumber ?? "" }), new Newtonsoft.Json.JsonSerializerSettings { StringEscapeHandling = Newtonsoft.Json.StringEscapeHandling.EscapeHtml })); } diff --git a/Web/Resgrid.Web/Areas/User/Views/Routes/New.cshtml b/Web/Resgrid.Web/Areas/User/Views/Routes/New.cshtml index a37c77664..0c71398e8 100644 --- a/Web/Resgrid.Web/Areas/User/Views/Routes/New.cshtml +++ b/Web/Resgrid.Web/Areas/User/Views/Routes/New.cshtml @@ -109,7 +109,7 @@

@localizer["Stops"] (0)

@@ -155,70 +155,70 @@
RouteStop NameAddressPriorityNotes@localizer["Route"]@localizer["StopName"]@localizer["AddressLabel"]@localizer["Priority"]@localizer["Notes"]
@switch (stop.Priority) { - case 1: High break; - case 2: Critical break; - case 3: Optional break; - default: Normal break; + case 1: @localizer["PriorityHigh"] break; + case 2: @localizer["PriorityCritical"] break; + case 3: @localizer["PriorityOptional"] break; + default: @localizer["PriorityNormal"] break; } @stop.Notes