diff --git a/Assets/Components/RoosterJS/roosterjs-9.7.0.tgz b/Assets/Components/RoosterJS/roosterjs-9.7.0.tgz new file mode 100644 index 0000000..2ea01b2 Binary files /dev/null and b/Assets/Components/RoosterJS/roosterjs-9.7.0.tgz differ diff --git a/ReadMe.md b/ReadMe.md index 052dfa6..5ff8570 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -28,37 +28,53 @@ The type of activity determines the sequence and period for which they are prese - Events: members of orgsniations allowed to manage events. - Opportunities: members of orgsniations allowed to manage opportunities. +### Data Components + +- Regions + - Hierarchy: World, Continents, Countries, Provinces +- Sports + - Specific sports (positions, disciplines etc) + - Banner (related) sports (Athletics - Track and Field, Swimmming - pool and wild). + - Grouped sports (Organisation supporting Baseball and Softball). + - Individual has interest and experience in specific and banner sports. + - Organisation identifies any level of sport as their remit. + - Relationships: parent holds list of child sports. + ### Application Components #### Styling -* Web resources: - * Colour analysis, including complementary etc. https://www.crispedge.com/color/556B2F +- Web resources: + - Colour analysis, including complementary etc. https://www.crispedge.com/color/556B2F ##### Online -* Colours: - * Base: #556B2F Dark Olive Green - * Darker: #445525, #33401c. Lighter: #768858, #99a682, #a6c275, #b7ce90. - +- Colours: + - Base: #556B2F Dark Olive Green + - Darker: #445525, #33401c. Lighter: #768858, #99a682, #a6c275, #b7ce90. #### Graphics -##### Icons - -- **Bootstrap**: https://icons.getbootstrap.com/ -- Where to find icons: https://www.canva.com/learn/free-icons-download/ -- https://icons8.com -- https://www.smashingmagazine.com/category/freebies -- https://goodstuffnononsense.com/icons-category/free/ -- https://www.iconfinder.com/ - -##### Animated gifs - -* https://icons8.com/preloaders/ +- Icons + - **Bootstrap**: https://icons.getbootstrap.com/ + - Where to find icons: https://www.canva.com/learn/free-icons-download/ + - https://icons8.com + - https://www.smashingmagazine.com/category/freebies + - https://goodstuffnononsense.com/icons-category/free/ + - https://www.iconfinder.com/ +- Animated gifs + - https://icons8.com/preloaders/ #### Page Functionality +##### Timepicker + +* JQuery TimePicker + * https://github.com/jonthornton/jquery-timepicker +* https://github.com/technovistalimited/bootstrap4-datetimepicker + * Requires moment.js: + * NuGet package contents can be found under **C:\\Users\\[user]\\.nuget\\packages\\moment.js** + ##### HTML Editor Controls - RoosterJS @@ -69,12 +85,13 @@ The type of activity determines the sequence and period for which they are prese - https://www.npmjs.com/package/roosterjs - distribution files. - https://registry.npmjs.org/roosterjs/latest - dist - tarball for download URL. - Download specific version: https://registry.npmjs.org/roosterjs/-/roosterjs-8.41.0.tgz -- TinyMCE - - NuGet package available but effectively doesn nothing - no longer able to copy script filles to aapplication folders. - - Manually copy files from: https://www.tiny.cloud/get-tiny/self-hosted/ ###### TinyMCE +- - TinyMCE + - NuGet package available but effectively does nothing - no longer able to copy script filles to aapplication folders. + - Manually copy files from: https://www.tiny.cloud/get-tiny/self-hosted/ + * HTML editor * Journallist Articles etc * Initialisation: diff --git a/SaxoniteCoreUnitTests/UnitTests/Web/Admin/App/SaxSessionData_Admin_Tester.cs b/SaxoniteCoreUnitTests/UnitTests/Web/Admin/App/SaxSessionData_Admin_Tester.cs index c7cf498..bed3e74 100644 --- a/SaxoniteCoreUnitTests/UnitTests/Web/Admin/App/SaxSessionData_Admin_Tester.cs +++ b/SaxoniteCoreUnitTests/UnitTests/Web/Admin/App/SaxSessionData_Admin_Tester.cs @@ -61,7 +61,7 @@ namespace Saxonite.Net.Core.UnitTests.Web.Admin.App idx = sessionData.NextItemIdx; // Serialise session data using same method as base controller. - String sessionDataJson = JsonConvert.SerializeObject(sessionData); + String sessionDataJson = NewtonsoftJsonUtil.SerializeObject(sessionData); Assert.AreNotEqual("", sessionDataJson); // Deserialise session data using same method as base controller. diff --git a/SaxoniteCoreWeb/Base/App/SaxLocaliser.cs b/SaxoniteCoreWeb/Base/App/SaxLocaliser.cs index 1b76605..57fb5cc 100644 --- a/SaxoniteCoreWeb/Base/App/SaxLocaliser.cs +++ b/SaxoniteCoreWeb/Base/App/SaxLocaliser.cs @@ -213,6 +213,12 @@ namespace Saxonite.Net.Core.Web.Base.App return GetCodeTypeCaption(Sax.CodeType.Gender, gender); } + // Sport Grouping. + public String GetSportGroupingCaption(Sax.SportGrouping sportGrouping) + { + return GetCodeTypeCaption(Sax.CodeType.SportGrouping, sportGrouping); + } + // Sport Speciality label. public String GetSportSpecialityLabelCaption(Sax.SportSpecialityLabel sportSpecialityLabel) { diff --git a/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs b/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs index 8c6dec6..41e990d 100644 --- a/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs +++ b/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs @@ -1,14 +1,20 @@ -using Sacs.Web.Components; +using Microsoft.AspNetCore.Mvc; +using Sacs.Web.Components; using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Bus; using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Email; +using Sarand.Net.Standard.Base.Utils; using Saxonite.Net.Core.Web.Base.App; using Saxonite.Net.Standard.Base.App; +using Saxonite.Net.Standard.Base.Bus; using Saxonite.Net.Standard.Base.Consoles; using Saxonite.Net.Standard.Base.Mgr; using Saxonite.Net.Standard.Base.Mgr.Reference; using Saxonite.Net.Standard.Base.Mgr.Support; +using System; using System.Collections.Generic; +using System.Linq; namespace Saxonite.Net.Core.Web.Base.Controllers { @@ -65,6 +71,7 @@ namespace Saxonite.Net.Core.Web.Base.Controllers public SaxSupportMgr SupportMgr { get { return Internals.SupportMgr; } } // System codes. public List DataItemTypeCodes { get { return Internals.DataItemTypeCodes; } } + public List SportGroupingCodes { get { return Internals.SportGroupingCodes; } } public List SportSpecialityLabelCodes { get { return Internals.SportSpecialityLabelCodes; } } public List SportContactTypeCodes { get { return Internals.SportContactTypeCodes; } } public List SportParticipatingCodes { get { return Internals.SportParticipatingCodes; } } @@ -88,6 +95,52 @@ namespace Saxonite.Net.Core.Web.Base.Controllers public SaEmailConfig EmailConfig { get { return App.EmailConfig; } } public SaxEmailConsole EmailConsole { get { return Internals.EmailConsole; } } + //------------------------------------------------------------------- + [NonAction] + /// + /// Retrieve sport by matching the name and include groups as required. + /// + /// + /// + /// List of matching sports. + public List GetSportsByName(String sportName, bool includeGroups = false) + { + List sportsData = new List(); + if (DataCacheConsole != null) + { + List allSports = DataCacheConsole.GetActiveSports(); + foreach (SaxSport.Data sport in allSports.Where(item => item.Name.EqualsCI(sportName))) + { + sportsData.Add(sport); + if (!includeGroups) continue; + foreach (SaxSport.Data sportParent in allSports.Where(item => item.Id.Equals(sport.SportIdParent))) + sportsData.Add(sportParent); + } + } + else + { + // Data cache is not available. + // Query direct from the database (Admin). + Dictionary sports = new Dictionary(); + + // Sport by name. + SaxSport.Params prmSport = new SaxSport.Params(); + prmSport.NameFull = sportName; + sports.AddRange(ReferenceMgr.GetSportList(prmSport).ToDictionary(item => item.Id)); + + if (includeGroups) + { + // Parent sports. + prmSport = new SaxSport.Params(); + prmSport.IdsIncluded.AddIds(sports.Values.Where(item => SysId.IsValid(item.SportIdParent)).Select(item => item.SportIdParent)); + if (prmSport.IdsIncluded.Any()) + sports.AddRange(ReferenceMgr.GetSportList(prmSport).ToDictionary(item => item.Id)); + } + sportsData = sports.Values.Select(item => item.GetData()).ToList(); + } + return sportsData; + } + //------------------------------------------------------------------- } //======================================================================= diff --git a/SaxoniteCoreWeb/Base/Controllers/SaxController_Web.cs b/SaxoniteCoreWeb/Base/Controllers/SaxController_Web.cs index e000cd3..35ab706 100644 --- a/SaxoniteCoreWeb/Base/Controllers/SaxController_Web.cs +++ b/SaxoniteCoreWeb/Base/Controllers/SaxController_Web.cs @@ -69,7 +69,7 @@ namespace Saxonite.Net.Core.Web.Base.Controllers // Some actions (eg. score password) don't need to. if (StoreSessionData) { - String sessionDataJson = JsonConvert.SerializeObject(SessionData); + String sessionDataJson = NewtonsoftJsonUtil.SerializeObject(SessionData); HttpContext.Session.Set(SessionStorage.SessionKey_SessionData, SessionStorage.sessionDataEncoding.GetBytes(sessionDataJson)); } } diff --git a/SaxoniteCoreWeb/Base/Models/SaxModel_Base.cs b/SaxoniteCoreWeb/Base/Models/SaxModel_Base.cs index cc8e7a1..a6dfc5b 100644 --- a/SaxoniteCoreWeb/Base/Models/SaxModel_Base.cs +++ b/SaxoniteCoreWeb/Base/Models/SaxModel_Base.cs @@ -73,6 +73,7 @@ namespace Saxonite.Net.Core.Web.Base.Models // System codes. public List DataItemTypeCodes { get { return Internals.DataItemTypeCodes; } } public List YesNoCodes { get { return Internals.YesNoCodes; } } + public List SportGroupingCodes { get { return Internals.SportGroupingCodes; } } public List SportSpecialityLabelCodes { get { return Internals.SportSpecialityLabelCodes; } } public List SportContactTypeCodes { get { return Internals.SportContactTypeCodes; } } public List SportParticipatingCodes { get { return Internals.SportParticipatingCodes; } } @@ -292,6 +293,18 @@ namespace Saxonite.Net.Core.Web.Base.Models } } + /// List of Sport Grouping for dropdown. + public IEnumerable SportGroupingCodesForSelect + { + get + { + List values = new List(); + foreach (TypeCodeDesc sportGrouping in SportGroupingCodes) + values.Add(new SelectListItem(Localiser.GetSportGroupingCaption((Sax.SportGrouping)sportGrouping.Type), sportGrouping.Code)); + return values; + } + } + /// List of Sport Speciality Labels for dropdown. public IEnumerable SportSpecialityLabelCodesForSelect { diff --git a/SaxoniteCoreWeb/Base/Procs/SaxGolfUsgaDataLookup-ScheduledUsgaDataLookup.cs b/SaxoniteCoreWeb/Base/Procs/SaxGolfUsgaDataLookup-ScheduledUsgaDataLookup.cs index 0d5305a..755e191 100644 --- a/SaxoniteCoreWeb/Base/Procs/SaxGolfUsgaDataLookup-ScheduledUsgaDataLookup.cs +++ b/SaxoniteCoreWeb/Base/Procs/SaxGolfUsgaDataLookup-ScheduledUsgaDataLookup.cs @@ -207,7 +207,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs // 5a. Active Country with no Provinces. { - bool populateCountryNoProvinces = SacsRandomHelper.GetInt32(1, 3) == 1; + bool populateCountryNoProvinces = SacsRandomHelper.GetInt32(1, 17) == 1; if (populateCountryNoProvinces) { SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params(); @@ -227,7 +227,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs // 5b. Active Province with no Facilities (courses). { - bool populateProvinceNoFacilities = SacsRandomHelper.GetInt32(1, 4) == 1; + bool populateProvinceNoFacilities = SacsRandomHelper.GetInt32(1, 3) == 1; if (populateProvinceNoFacilities) { // Active Provinces with no Facilities. @@ -307,7 +307,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs List annotations = new List(); if (usgaCourse.Priority) annotations.Add("Priority"); if (fallback) annotations.Add("Fallback"); - SaLogger.Info($"{SysUtil.Fn} USGA Markers " + (refresh ? "refreshed" : "populated") + $" for {usgaCountry.CountryCode} {usgaCountry.CountryName} - {usgaProvince.ProvinceCode} {usgaProvince.ProvinceName} - {usgaCourse.Caption} [Id: {usgaCourse.UsgaCourseId}" + (annotations.Any() ? $"{annotations.Concat("",", ")}" : "") + $"]: {markersData.Count}.", true); + SaLogger.Info($"{SysUtil.Fn} USGA Markers " + (refresh ? "refreshed" : "populated") + $" for {usgaCountry.CountryCode} {usgaCountry.CountryName} - {usgaProvince.ProvinceCode} {usgaProvince.ProvinceName} - {usgaCourse.Caption} [Id: {usgaCourse.UsgaCourseId}" + (annotations.Any() ? $"{annotations.Concat("", ", ")}" : "") + $"]: {markersData.Count}.", true); } else SaLogger.Error($"{SysUtil.Fn} Missing Country for Province {usgaProvince.ProvinceName}. Country Id: {usgaProvince.CountryId}."); } diff --git a/SaxoniteCoreWeb/Base/Procs/SaxGolfUsgaDataLookup.cs b/SaxoniteCoreWeb/Base/Procs/SaxGolfUsgaDataLookup.cs index 572f623..70cea1c 100644 --- a/SaxoniteCoreWeb/Base/Procs/SaxGolfUsgaDataLookup.cs +++ b/SaxoniteCoreWeb/Base/Procs/SaxGolfUsgaDataLookup.cs @@ -11,6 +11,7 @@ using Sarand.Net.Standard.Base.Dbas; using Sarand.Net.Standard.Base.Helpers; using Sarand.Net.Standard.Base.Net; using Sarand.Net.Standard.Base.Utils; +using Saxonite.Net.Core.Web.Base.Controllers; using Saxonite.Net.Standard.Base.App; using Saxonite.Net.Standard.Base.Bus.Reference; using Saxonite.Net.Standard.Base.Mgr.Reference; @@ -33,13 +34,18 @@ namespace Saxonite.Net.Core.Web.Base.Procs // Definitions. public enum Task { - CleanseCourseCaptions, + CleanseCourses, + CleanseMarkers } public new class Config : SaxProcess_Web.Config { public Config(SaxSessionContext sessionContext, DbUpdateInfo dbUpdateInfo) : base(sessionContext, dbUpdateInfo) { } + /// Restrict countries by Id. + public HashSet UsgaCountryIdsIncluded { get; } = new HashSet(); + /// Restrict countries by Code. + public HashSet UsgaCountryCodesIncluded { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); /// Tasks to be run under this instance of the USGA Data Lookup process. public HashSet Tasks { get; } = new HashSet(); } @@ -108,12 +114,31 @@ namespace Saxonite.Net.Core.Web.Base.Procs public class MarkerData { + [JsonConstructor] + private MarkerData() { } public MarkerData(SysId courseId, short holes, string holesCaption) { this.CourseId = courseId; this.Holes = holes; this.HolesCaption = holesCaption; } + public MarkerData(SaxGolfUsgaCourse course, SaxGolfUsgaMarker marker) : this(course.UsgaCourseId, marker) + { + } + public MarkerData(SysId usgaCourseId, SaxGolfUsgaMarker marker) + { + this.CourseId = usgaCourseId; + this.CourseId = marker.UsgaMarkerId; + this.Holes = marker.Holes; + this.HolesCaption = marker.HolesCaption; + this.Tee = marker.Tee; + this.Gender = marker.Gender; + this.SlopeRating = marker.SlopeRating; + this.Par = marker.Par; + this.CourseRating = marker.CourseRating; + this.BogeyRating = marker.BogeyRating; + this.Length = marker.Length; + } public SysId CourseId { get; } public SysId MarkerId { get; set; } public string Caption { get { return StringUtil.TrimWhitespace(StringUtil.OnBlank(Tee) + " " + StringUtil.OnBlank(HolesCaption) + " " + StringUtil.OnBlank(Gender)); } } @@ -166,8 +191,11 @@ namespace Saxonite.Net.Core.Web.Base.Procs { switch (task) { - case Task.CleanseCourseCaptions: - CleanseCourseCaptions(); + case Task.CleanseCourses: + CleanseCourses(); + break; + case Task.CleanseMarkers: + CleanseMarkers(); break; } if (!OK) break; @@ -307,8 +335,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs countryData.CountryName = usgaCountry.Name; countriesData.Add(countryData); } - ReferenceGolfMgr.BulkUpdateUsgaCountries(countriesData, DbUpdateInfo); - if (ReferenceGolfMgr.HasErrorState()) + if (!ReferenceGolfMgr.BulkUpdateUsgaCountries(countriesData, DbUpdateInfo)) SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA countries: {ReferenceGolfMgr.ErrorStateMessage}."); } @@ -333,7 +360,9 @@ namespace Saxonite.Net.Core.Web.Base.Procs using (DisposableCollection disposableItems = new DisposableCollection()) { // Retrieve and validate country. - SaxGolfUsgaCountry usgaCountry = ReferenceGolfMgr.GetUsgaCountry(new SaxGolfUsgaCountry.Params() { CountryCodeFull = countryCode }); + SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params(); + prmCountry.CountryCodesIncluded.Add(countryCode); + SaxGolfUsgaCountry usgaCountry = ReferenceGolfMgr.GetUsgaCountry(prmCountry); disposableItems.Add(usgaCountry); if (usgaCountry == null) { @@ -344,7 +373,8 @@ namespace Saxonite.Net.Core.Web.Base.Procs { // Clear country 'priority' flag. usgaCountry.Priority = false; - ReferenceGolfMgr.UpdateUsgaCountry(usgaCountry, DbUpdateInfo); + if (!ReferenceGolfMgr.UpdateUsgaCountry(usgaCountry, DbUpdateInfo)) + SaLogger.Warn($"{SysUtil.Fn} Error updating Country '{usgaCountry.CountryCode}' - {ReferenceGolfMgr.ErrorStateMessage}"); } try @@ -417,7 +447,8 @@ namespace Saxonite.Net.Core.Web.Base.Procs // Provinces stored OK = update Country. usgaCountry.ProvincesUpdateAt = DateTime.Now; usgaCountry.Priority = false; - ReferenceGolfMgr.UpdateUsgaCountry(usgaCountry, DbUpdateInfo); + if (!ReferenceGolfMgr.UpdateUsgaCountry(usgaCountry, DbUpdateInfo)) + SaLogger.Warn($"{SysUtil.Fn} Error updating Country '{usgaCountry.CountryCode}' - {ReferenceGolfMgr.ErrorStateMessage}"); } else SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA provinces: {ReferenceGolfMgr.ErrorStateMessage}."); } @@ -443,7 +474,9 @@ namespace Saxonite.Net.Core.Web.Base.Procs using (DisposableCollection disposableItems = new DisposableCollection()) { // Retrieve and validate country. - SaxGolfUsgaCountry usgaCountry = ReferenceGolfMgr.GetUsgaCountry(new SaxGolfUsgaCountry.Params() { CountryCodeFull = countryCode }); + SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params(); + prmCountry.CountryCodesIncluded.Add(countryCode); + SaxGolfUsgaCountry usgaCountry = ReferenceGolfMgr.GetUsgaCountry(prmCountry); disposableItems.Add(usgaCountry); if (usgaCountry == null) { @@ -462,7 +495,8 @@ namespace Saxonite.Net.Core.Web.Base.Procs { // Clear province 'priority' flag. usgaProvince.Priority = false; - ReferenceGolfMgr.UpdateUsgaProvince(usgaProvince, DbUpdateInfo); + if (!ReferenceGolfMgr.UpdateUsgaProvince(usgaProvince, DbUpdateInfo)) + SaLogger.Warn($"{SysUtil.Fn} Error updating Province '{usgaProvince.ProvinceCode}' - {ReferenceGolfMgr.ErrorStateMessage}"); } try @@ -492,7 +526,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs if (!StringUtil.IsBlank(response.Data)) { - HashSet UnrecognisedCourseProperties = new HashSet(StringComparer.InvariantCultureIgnoreCase); + HashSet UnrecognisedCourseProperties = new HashSet(StringComparer.OrdinalIgnoreCase); dynamic coursesJson = SacsJsonHelper.DeserializeJsonObject(response.Data); if (coursesJson is JArray) { @@ -569,8 +603,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs countryData.EntCountryCode = usgaCourse.EntCountryCode; countriesData[countryData.CountryCode] = countryData; } - ReferenceGolfMgr.BulkUpdateUsgaCountries(countriesData.Values.ToList(), DbUpdateInfo); - if (ReferenceGolfMgr.HasErrorState()) + if (!ReferenceGolfMgr.BulkUpdateUsgaCountries(countriesData.Values.ToList(), DbUpdateInfo)) SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA countries: {ReferenceGolfMgr.ErrorStateMessage}."); // Store provinces. @@ -583,8 +616,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs provinceData.EntProvinceCode = usgaCourse.EntProvinceCode; provincesData[provinceData.ProvinceCode] = provinceData; } - ReferenceGolfMgr.BulkUpdateUsgaProvinces(provincesData.Values.ToList(), DbUpdateInfo); - if (ReferenceGolfMgr.HasErrorState()) + if (!ReferenceGolfMgr.BulkUpdateUsgaProvinces(provincesData.Values.ToList(), DbUpdateInfo)) SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA provinces: {ReferenceGolfMgr.ErrorStateMessage}."); // Store facilities. @@ -603,8 +635,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs } facilitiesData[facilityData.UsgaFacilityId] = facilityData; } - ReferenceGolfMgr.BulkUpdateUsgaFacilities(facilitiesData.Values.ToList(), DbUpdateInfo); - if (ReferenceGolfMgr.HasErrorState()) + if (!ReferenceGolfMgr.BulkUpdateUsgaFacilities(facilitiesData.Values.ToList(), DbUpdateInfo)) SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA facilities: {ReferenceGolfMgr.ErrorStateMessage}."); // Store courses. @@ -637,7 +668,8 @@ namespace Saxonite.Net.Core.Web.Base.Procs // Courses stored OK - update Province. usgaProvince.CoursesUpdateAt = DateTime.Now; usgaProvince.Priority = false; - ReferenceGolfMgr.UpdateUsgaProvince(usgaProvince, DbUpdateInfo); + if (!ReferenceGolfMgr.UpdateUsgaProvince(usgaProvince, DbUpdateInfo)) + SaLogger.Warn($"{SysUtil.Fn} Error updating Province '{usgaProvince.ProvinceCode}' - {ReferenceGolfMgr.ErrorStateMessage}"); } else SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA courses: {ReferenceGolfMgr.ErrorStateMessage}."); } @@ -715,7 +747,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs } //------------------------------------------------------------------ - public bool CleanseCourseCaptions() + public bool CleanseCourses() { SaLogger.Info($"{SysUtil.Fn} START", true); DateTime startedAt = DateTime.Now; @@ -729,10 +761,13 @@ namespace Saxonite.Net.Core.Web.Base.Procs using (DisposableCollection disposables = new DisposableCollection()) { // Local function to allow break/return from within nested loop. - void CompareCourseCaptions() + void CompareCourse() { // Countries. - foreach (SaxGolfUsgaCountry country in ReferenceGolfMgr.GetUsgaCountryList(new SaxGolfUsgaCountry.Params())) + SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params(); + prmCountry.IdsIncluded.AddIds(config.UsgaCountryIdsIncluded); + prmCountry.CountryCodesIncluded.UnionWith(config.UsgaCountryCodesIncluded); + foreach (SaxGolfUsgaCountry country in ReferenceGolfMgr.GetUsgaCountryList(prmCountry)) { disposables.Add(country); @@ -750,6 +785,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs // Facilities. SaxGolfUsgaFacility.Params prmFacility = new SaxGolfUsgaFacility.Params(); prmFacility.ProvinceIdsIncluded.Add(province.Id); + prmFacility.HasCourses = SacsHierarchyItem.Params.BoolState.True; foreach (SaxGolfUsgaFacility facility in ReferenceGolfMgr.GetUsgaFacilityList(prmFacility)) { disposablesProvince.Add(facility); @@ -770,7 +806,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs if (ReferenceGolfMgr.UpdateUsgaCourse(course, DbUpdateInfo)) { courseCaptionsCorrected++; - SaLogger.Info($"{SysUtil.Fn} Course caption corrected. Found: {course.Caption}.Corrected: {courseCaption}."); + SaLogger.Info($"{SysUtil.Fn} Course caption corrected. Found: {course.Caption}. Corrected: {courseCaption}."); } else { @@ -791,7 +827,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs } } // Invoke local function. - CompareCourseCaptions(); + CompareCourse(); } // Log statistics. @@ -855,7 +891,8 @@ namespace Saxonite.Net.Core.Web.Base.Procs if (usgaCourse.Priority) { usgaCourse.Priority = false; - ReferenceGolfMgr.UpdateUsgaCourse(usgaCourse, DbUpdateInfo); + if (!ReferenceGolfMgr.UpdateUsgaCourse(usgaCourse, DbUpdateInfo)) + SaLogger.Warn($"{SysUtil.Fn} Error updating Course '{usgaCourse.FullName}' - {ReferenceGolfMgr.ErrorStateMessage}"); } try @@ -1049,10 +1086,11 @@ namespace Saxonite.Net.Core.Web.Base.Procs { // Markers stored OK - update Course. if (markersData.Markers.Any()) - usgaCourse.MarkersData = JsonConvert.SerializeObject(markersData); + usgaCourse.MarkersData = NewtonsoftJsonUtil.SerializeObject(markersData, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); usgaCourse.MarkersUpdateAt = DateTime.Now; usgaCourse.Priority = false; - ReferenceGolfMgr.UpdateUsgaCourse(usgaCourse, DbUpdateInfo); + if (!ReferenceGolfMgr.UpdateUsgaCourse(usgaCourse, DbUpdateInfo)) + SaLogger.Warn($"{SysUtil.Fn} Error updating Course '{usgaCourse.FullName}' - {ReferenceGolfMgr.ErrorStateMessage}"); } else SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA markers: {ReferenceGolfMgr.ErrorStateMessage}."); } @@ -1065,6 +1103,182 @@ namespace Saxonite.Net.Core.Web.Base.Procs } //------------------------------------------------------------------ + + /// + /// Front and Back 9 likely missing par values - derive from other properties. + /// + /// Marker to have its par calulated. + /// Full list of markers for the course. + /// + private short CalculateMarkerParByCourseRating(MarkerData marker, List markers) + { + if (marker.Holes > 9) return marker.Par; + + // Locate the corresponding marker for the other half of the course (F9/B9). + String holesCaptionOpp = marker.HolesCaption.EqualsCI("F9") ? "B9" : marker.HolesCaption.EqualsCI("B9") ? "F9" : ""; + MarkerData marker18 = markers.Find(item => item.Holes == 18 && item.Tee == marker.Tee && item.Gender == marker.Gender); + MarkerData markerOpp = markers.Find(item => item.HolesCaption.EqualsCI(holesCaptionOpp) && item.Tee == marker.Tee && item.Gender == marker.Gender); + if (marker18 != null && markerOpp != null) + { + decimal combined9sCourseRating = marker.CourseRating + markerOpp.CourseRating; + return (short)Math.Round(marker18.Par * marker.CourseRating / combined9sCourseRating); + } + return marker.Par; + } + + /// + /// Front and Back 9 likely missing par values - derive from other properties. + /// + /// Marker to have its par calulated. + /// Full list of markers for the course. + /// + private short CalculateMarkerParBySlopeRating(MarkerData marker, List markers) + { + if (marker.Holes > 9) return marker.Par; + + // Locate the corresponding marker for the other half of the course (F9/B9). + String holesCaptionOpp = marker.HolesCaption.EqualsCI("F9") ? "B9" : marker.HolesCaption.EqualsCI("B9") ? "F9" : ""; + MarkerData marker18 = markers.Find(item => item.Holes == 18 && item.Tee == marker.Tee && item.Gender == marker.Gender); + MarkerData markerOpp = markers.Find(item => item.HolesCaption.EqualsCI(holesCaptionOpp) && item.Tee == marker.Tee && item.Gender == marker.Gender); + if (marker18 != null && markerOpp != null) + { + decimal combined9sSlopeRating = marker.SlopeRating + markerOpp.SlopeRating; + return (short)Math.Round(marker18.Par * marker.SlopeRating / combined9sSlopeRating); + } + return marker.Par; + } + + //------------------------------------------------------------------ + public bool CleanseMarkers() + { + SaLogger.Info($"{SysUtil.Fn} START", true); + DateTime startedAt = DateTime.Now; + ClearProcessMessages(); + + int markerCount = 0; + int courseCount = 0; + int maxMarkers = 0; + int markersCorrected = 0; + + using (DisposableCollection disposables = new DisposableCollection()) + { + // Local function to allow break/return from within nested loop. + void CleanseMarkers() + { + // Countries. + SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params(); + prmCountry.IdsIncluded.AddIds(config.UsgaCountryIdsIncluded); + prmCountry.CountryCodesIncluded.UnionWith(config.UsgaCountryCodesIncluded); + foreach (SaxGolfUsgaCountry country in ReferenceGolfMgr.GetUsgaCountryList(prmCountry)) + { + disposables.Add(country); + + // Provinces. + SaxGolfUsgaProvince.Params prmProvince = new SaxGolfUsgaProvince.Params(); + prmProvince.CountryIdsIncluded.Add(country.Id); + foreach (SaxGolfUsgaProvince province in ReferenceGolfMgr.GetUsgaProvinceList(prmProvince)) + { + disposables.Add(province); + + // Separate disposables for each province to restrict volume handled on each disposal. + using (DisposableCollection disposablesProvince = new DisposableCollection()) + { + + // Facilities. + SaxGolfUsgaFacility.Params prmFacility = new SaxGolfUsgaFacility.Params(); + prmFacility.ProvinceIdsIncluded.Add(province.Id); + foreach (SaxGolfUsgaFacility facility in ReferenceGolfMgr.GetUsgaFacilityList(prmFacility)) + { + disposablesProvince.Add(facility); + + // Courses. + SaxGolfUsgaCourse.Params prmCourse = new SaxGolfUsgaCourse.Params(); + prmCourse.FacilityIdsIncluded.Add(facility.Id); + prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.True; + foreach (SaxGolfUsgaCourse course in ReferenceGolfMgr.GetUsgaCourseList(prmCourse)) + { + disposablesProvince.Add(course); + courseCount++; + int markersModified = 0; + + // Extract markers from data. + MarkersData markersData = null; + try + { + markersData = JsonConvert.DeserializeObject(course.MarkersData, new JsonSerializerSettings() { }); + } + catch (Exception exc) + { + SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetLogMessage(exc, 4)}"); + } + markersData = markersData ?? new MarkersData(); + + // Markers. + SaxGolfUsgaMarker.Params prmMarker = new SaxGolfUsgaMarker.Params(); + prmMarker.CourseIdsIncluded.Add(course.Id); + List markers = ReferenceGolfMgr.GetUsgaMarkerList(prmMarker); + + if (!markersData.Markers.Any() && markers.Any()) + { + // Generate Markers data from stored markers. + SaLogger.Warn($"{SysUtil.Fn} Regenerating missing markers data. Course: {country.CountryCode} {province.ProvinceCode} {course.Caption}."); + markersData = new MarkersData(); + foreach (SaxGolfUsgaMarker marker in markers) + markersData.Markers.Add(new MarkerData(course.UsgaCourseId, marker)); + } + markerCount += markersData.Markers.Count; + + // Validate number of markers against data. + if (markers.Count != markersData.Markers.Count) + { + SaLogger.Warn($"{SysUtil.Fn} Inconsistent marker count. Course: {country.CountryCode} {province.ProvinceCode} {course.Caption}. Markers data: {markersData.Markers.Count}. Markers: {markers.Count}."); + continue; + } + markerCount += markersData.Markers.Count; + + foreach (MarkerData markerData in markersData.Markers) + { + // Calulate Par by Course Rating. + short parCalulatedByCourseRating = CalculateMarkerParByCourseRating(markerData, markersData.Markers); + if (markerData.Par != parCalulatedByCourseRating) + { + SaLogger.Warn($"{SysUtil.Fn} Marker par recalculated by Course Rating. Course: {country.CountryCode} {province.ProvinceCode} {course.Caption}. Marker: {markerData.Tee} {markerData.HolesCaption} {markerData.Gender}. Par found: {markerData.Par}. Recalculated: {parCalulatedByCourseRating}."); + //markerData.Par = parCalulated; + // markersModified ++; + } + + // Calulate Par by Slope Rating. + short parCalulatedBySlopeRating = CalculateMarkerParBySlopeRating(markerData, markersData.Markers); + if (markerData.Par != parCalulatedBySlopeRating) + { + SaLogger.Warn($"{SysUtil.Fn} Marker par recalculated by Slope Rating. Course: {country.CountryCode} {province.ProvinceCode} {course.Caption}. Marker: {markerData.Tee} {markerData.HolesCaption} {markerData.Gender}. Par found: {markerData.Par}. Recalculated: {parCalulatedBySlopeRating}."); + //markerData.Par = parCalulated; + // markersModified ++; + } + } + + if (markersModified > 0) + { + // ToDo Bulk update the markers to apply changes. + } + } + } + } + } + } + } + // Invoke local function. + CleanseMarkers(); + } + + // Log statistics. + SaLogger.Info($"{SysUtil.Fn} Markers corrected: {markersCorrected}. Markers checked: {markerCount}.", true); + + SaLogger.Info($"{SysUtil.Fn} END Elapsed: {DateUtil.FormatNumberOfSeconds((DateTime.Now - startedAt).TotalSeconds)}", true); + return OK; + } + + //------------------------------------------------------------------ } //====================================================================== } diff --git a/SaxoniteCoreWeb/SaxoniteCoreWeb.csproj b/SaxoniteCoreWeb/SaxoniteCoreWeb.csproj index f7a0691..26de12f 100644 --- a/SaxoniteCoreWeb/SaxoniteCoreWeb.csproj +++ b/SaxoniteCoreWeb/SaxoniteCoreWeb.csproj @@ -24,7 +24,7 @@ - + diff --git a/SaxoniteCoreWebAdmin/Admin/App/SaxApplication_Admin.cs b/SaxoniteCoreWebAdmin/Admin/App/SaxApplication_Admin.cs index b1f9ecf..5a122ef 100644 --- a/SaxoniteCoreWebAdmin/Admin/App/SaxApplication_Admin.cs +++ b/SaxoniteCoreWebAdmin/Admin/App/SaxApplication_Admin.cs @@ -31,7 +31,7 @@ namespace Saxonite.Net.Core.Web.Admin.App { //------------------------------------------------------------------- // Data members. - private bool generateDatabaseDefinitions = false; + private bool generateDatabaseDefinitions = true; private bool populateRegions = false; private Dictionary appConfigs = new Dictionary(); private Dictionary emailConfigs = new Dictionary(); diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Images-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Images.cs similarity index 93% rename from SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Images-Ajax.cs rename to SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Images.cs index b80ccde..14d33b8 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Images-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Images.cs @@ -19,7 +19,7 @@ using System.Threading.Tasks; namespace Saxonite.Net.Core.Web.Admin.Controllers { //======================================================================= - // Controller: Organisation Images - Ajax + // Controller: Organisation - Ajax - Images //======================================================================= partial class OrganisationController { @@ -156,18 +156,28 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers imageData = fileStream.ToArray(); } + // Validate content type. + if (StringUtil.IsEmpty(file.ContentType) || !SaxItemImage.GetValidContentTypes(Sax.DataItemType.Organisation).ContainsCI(file.ContentType)) + return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid.content.type"])); + Sarand.Net.Standard.Base.Core.Sacs.MimeType mimeTypeExpected = SacsContentTypeHelper.GetMimeTypeFromContentType(file.ContentType); + // Validate the image. - ImageUtils.ImageConfig imageConfig = ImageUtils.VerifyImageData(imageData); + ImageUtils.ImageConfig imageConfig = null; + if (mimeTypeExpected == Sarand.Net.Standard.Base.Core.Sacs.MimeType.Svg) + imageConfig = ImageUtils.VerifySvgImageData(imageData); + else + imageConfig = ImageUtils.VerifyImageData(imageData); if (!imageConfig.ValidImage) return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid"])); // Validate mime type. - if (!SaxItemImage.GetValidMimeTypes(Sax.DataItemType.UserAccount).Contains(imageConfig.MimeType)) + if (!SaxItemImage.GetValidMimeTypes(Sax.DataItemType.Organisation).Contains(imageConfig.MimeType)) return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid.mime"])); - - // Validate content type. - if (StringUtil.IsEmpty(file.ContentType) || !SaxItemImage.GetValidContentTypes(Sax.DataItemType.UserAccount).ContainsCI(file.ContentType)) - return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid.content.type"])); + if (imageConfig.MimeType != mimeTypeExpected) + { + SaLogger.Warn($"{SysUtil.Fn} Image upload - inconsistent Mime. Filename: {file.FileName}. Mime: {imageConfig.MimeType}. Expected Mime: {mimeTypeExpected}."); + return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid"])); + } // Resize the image if required. if (!ImageUtils.ConstrainImage(imageConfig, Sax.Config.Organisation.Logo.WidthMax, Sax.Config.Organisation.Logo.HeightMax)) diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceBaseballController .cs b/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceBaseballController .cs new file mode 100644 index 0000000..4496c08 --- /dev/null +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceBaseballController .cs @@ -0,0 +1,46 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Saxonite.Net.Core.Web.Admin.Models.Reference; +using Saxonite.Net.Core.Web.Base.App; +using Saxonite.Net.Core.Web.Base.Controllers; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; + +namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference +{ + //======================================================================= + public partial class ReferenceBaseballController : SaxController_Admin + { + //------------------------------------------------------------------- + // Construction. + public ReferenceBaseballController(SaxLocaliser localiser, ILogger logger) : + base(localiser, logger) + { + } + + //------------------------------------------------------------------- + [HttpGet] + [Route("Reference/Baseball")] + public IActionResult Index() + { + // Validate session. + if (!ValidUserSession) + AutoLoginUser(); + if (!ValidUserSession) + return RedirectToAction("", ""); + + // Paging. + Model_ReferenceBaseball model = new Model_ReferenceBaseball(Localiser); + //model.Paging.PageNo = 1; + //model.Paging.PageLength = 12; + + return View("/Views/Reference/Baseball/Index.cshtml",model); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceBaseballController-Ajax-Stats.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceBaseballController-Ajax-Stats.cs new file mode 100644 index 0000000..03e678a --- /dev/null +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceBaseballController-Ajax-Stats.cs @@ -0,0 +1,76 @@ +using Microsoft.AspNetCore.Mvc; +using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Bus; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Dbas; +using Sarand.Net.Standard.Base.Utils; +using Saxonite.Net.Core.Web.Admin.Models; +using Saxonite.Net.Core.Web.Admin.Models.Reference; +using Saxonite.Net.Standard.Base.App; +using Saxonite.Net.Standard.Base.Bus; +using Saxonite.Net.Standard.Base.Bus.Reference; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference +{ + //======================================================================= + // Reference Baseball Controller - Ajax requests - Stats. + //======================================================================= + partial class ReferenceBaseballController + { + //------------------------------------------------------------------- + // Get Stats ajax request. + //------------------------------------------------------------------- + private class AjaxResponse_ReferenceBaseballStats : AjaxResponse_Data + { + // Construction. + public AjaxResponse_ReferenceBaseballStats(SaxModel_Admin model) : base(model) { } + // Statistics. + public List Groups { get; } = new List(); + } + //------------------------------------------------------------------- + [HttpPost] + [Route("Reference/Baseball/Ajax/GetStats")] + [Route("Reference/Baseball/Ajax/Stats")] + public IActionResult Ajax_GetUsgaStats(Model_ReferenceBaseball model) + { + String fn = GetType().Name + ".Ajax_GetUsgaStats"; + String messageTitle = Localiser["caption.reference.baseball"]; + AjaxResponse_ReferenceBaseballStats responseData = new AjaxResponse_ReferenceBaseballStats(model); + + // Validate session. + if (!ValidUserSession) + return GetAjaxResult_InvalidSession(responseData); + + // Statistics. + responseData.Groups.Add(PopulateCoreStatsData(model)); + + // Complete response. + responseData.Success = true; + return Json(responseData); + } + + //------------------------------------------------------------------- + private AjaxResponse_Data.StatsGroupData PopulateCoreStatsData(Model_ReferenceBaseball model) + { + AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Core" }; + + // Sports. + List sports = GetSportsByName("Baseball", true); + + // Organisations. + SaxOrganisation.Params prmOrganisation = new SaxOrganisation.Params(); + prmOrganisation.SportIdsIncluded.AddIds(sports.Select(item => item.Id)); + prmOrganisation.StatusCat = SaxOrganisation.StatusCat.ActiveOnly; + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active Organisations", Value = AccountMgr.GetOrganisationCount(prmOrganisation).ToString() }); + + return group; + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceBaseballController-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceBaseballController-Ajax.cs new file mode 100644 index 0000000..8acade4 --- /dev/null +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceBaseballController-Ajax.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; +using NPOI.SS.Formula.Functions; +using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Bus; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Dbas; +using Sarand.Net.Standard.Base.Utils; +using Saxonite.Net.Core.Web.Admin.Consoles; +using Saxonite.Net.Core.Web.Admin.Models; +using Saxonite.Net.Core.Web.Admin.Models.Reference; +using Saxonite.Net.Core.Web.Admin.Procs; +using Saxonite.Net.Core.Web.Base.Procs; +using Saxonite.Net.Standard.Base.App; +using Saxonite.Net.Standard.Base.Bus; +using Saxonite.Net.Standard.Base.Bus.Reference; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference +{ + //======================================================================= + // Reference Baseball Controller - Ajax requests. + //======================================================================= + partial class ReferenceBaseballController + { + //------------------------------------------------------------------- + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceGolfController-Ajax-Stats.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceGolfController-Ajax-Stats.cs index 1d3a4a1..41e7910 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceGolfController-Ajax-Stats.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceGolfController-Ajax-Stats.cs @@ -16,10 +16,10 @@ using System.Threading.Tasks; namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference { - //======================================================================= - // Reference Golf Controller - Ajax requests. - //======================================================================= - partial class ReferenceGolfController + //======================================================================= + // Reference Golf Controller - Ajax requests - Stats. + //======================================================================= + partial class ReferenceGolfController { //------------------------------------------------------------------- // Get Stats ajax request. @@ -29,17 +29,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference // Construction. public AjaxResponse_ReferenceGolfStats(SaxModel_Admin model) : base(model) { } // Statistics. - public class StatData : AjaxResponse_Base - { - public String Caption { get; set; } - public String Value { get; set; } - } - public class StatGroupData : AjaxResponse_Base - { - public String Caption { get; set; } - public List Stats { get; } = new List(); - } - public List Groups { get; } = new List(); + public List Groups { get; } = new List(); } //------------------------------------------------------------------- [HttpPost] @@ -69,237 +59,237 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference } //------------------------------------------------------------------- - private AjaxResponse_ReferenceGolfStats.StatGroupData PopulateCountryStatsData() + private AjaxResponse_Data.StatsGroupData PopulateCountryStatsData() { - AjaxResponse_ReferenceGolfStats.StatGroupData group = new AjaxResponse_ReferenceGolfStats.StatGroupData() { Caption = "Countries" }; + AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Countries" }; // All countries. SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params(); prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.Any; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); // Active countries. prmCountry = new SaxGolfUsgaCountry.Params(); prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); // Inctive countries. prmCountry = new SaxGolfUsgaCountry.Params(); prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.InactiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); // Deleted countries. prmCountry = new SaxGolfUsgaCountry.Params(); prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.DeletedOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); // Priority countries without provinces. prmCountry = new SaxGolfUsgaCountry.Params(); prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True; prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.False; prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Priority no provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority no provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); // Non-Priority countries without provinces. prmCountry = new SaxGolfUsgaCountry.Params(); prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False; prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.False; prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Non-priority no provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority no provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); // Priority countries with provinces. prmCountry = new SaxGolfUsgaCountry.Params(); prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True; prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.True; prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Priority with provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority with provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); // Non-Priority countries with provinces. prmCountry = new SaxGolfUsgaCountry.Params(); prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False; prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.True; prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Non-priority with provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority with provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() }); return group; } //------------------------------------------------------------------- - private AjaxResponse_ReferenceGolfStats.StatGroupData PopulateProvinceStatsData() + private AjaxResponse_Data.StatsGroupData PopulateProvinceStatsData() { - AjaxResponse_ReferenceGolfStats.StatGroupData group = new AjaxResponse_ReferenceGolfStats.StatGroupData() { Caption = "Provinces" }; + AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Provinces" }; // All provinces. SaxGolfUsgaProvince.Params prmProvince = new SaxGolfUsgaProvince.Params(); prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.Any; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); // Active provinces. prmProvince = new SaxGolfUsgaProvince.Params(); prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); // Inctive provinces. prmProvince = new SaxGolfUsgaProvince.Params(); prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.InactiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); // Deleted provinces. prmProvince = new SaxGolfUsgaProvince.Params(); prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.DeletedOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); // Priority provinces without facilities. prmProvince = new SaxGolfUsgaProvince.Params(); prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True; prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.False; prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Priority no facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority no facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); // Non-Priority provinces without facilities. prmProvince = new SaxGolfUsgaProvince.Params(); prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False; prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.False; prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Non-priority no facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority no facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); // Priority provinces with facilities. prmProvince = new SaxGolfUsgaProvince.Params(); prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True; prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.True; prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Priority with facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority with facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); // Non-Priority provinces with facilities. prmProvince = new SaxGolfUsgaProvince.Params(); prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False; prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.True; prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Non-priority with facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority with facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() }); return group; } //------------------------------------------------------------------- - private AjaxResponse_ReferenceGolfStats.StatGroupData PopulateFacilityStatsData() + private AjaxResponse_Data.StatsGroupData PopulateFacilityStatsData() { - AjaxResponse_ReferenceGolfStats.StatGroupData group = new AjaxResponse_ReferenceGolfStats.StatGroupData() { Caption = "Facilities" }; + AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Facilities" }; // All facilities. SaxGolfUsgaFacility.Params prmFacility = new SaxGolfUsgaFacility.Params(); prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.Any; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); // Active facilities. prmFacility = new SaxGolfUsgaFacility.Params(); prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); // Inctive facilities. prmFacility = new SaxGolfUsgaFacility.Params(); prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.InactiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); // Deleted facilities. prmFacility = new SaxGolfUsgaFacility.Params(); prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.DeletedOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); // Facilities without courses. prmFacility = new SaxGolfUsgaFacility.Params(); prmFacility.HasCourses = SacsHierarchyItem.Params.BoolState.False; prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "No courses", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "No courses", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); // Priority facilities with courses. prmFacility = new SaxGolfUsgaFacility.Params(); prmFacility.HasCourses = SacsHierarchyItem.Params.BoolState.True; prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "With courses", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "With courses", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() }); return group; } //------------------------------------------------------------------- - private AjaxResponse_ReferenceGolfStats.StatGroupData PopulateCourseStatsData() + private AjaxResponse_Data.StatsGroupData PopulateCourseStatsData() { - AjaxResponse_ReferenceGolfStats.StatGroupData group = new AjaxResponse_ReferenceGolfStats.StatGroupData() { Caption = "Courses" }; + AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Courses" }; // All courses. SaxGolfUsgaCourse.Params prmCourse = new SaxGolfUsgaCourse.Params(); prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.Any; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); // Active courses. prmCourse = new SaxGolfUsgaCourse.Params(); prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); // Inctive courses. prmCourse = new SaxGolfUsgaCourse.Params(); prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.InactiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); // Deleted courses. prmCourse = new SaxGolfUsgaCourse.Params(); prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.DeletedOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); // Priority courses without markers. prmCourse = new SaxGolfUsgaCourse.Params(); prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True; prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.False; prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Priority no markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority no markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); // Non-Priority courses without markers. prmCourse = new SaxGolfUsgaCourse.Params(); prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False; prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.False; prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Non-priority no markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority no markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); // Priority courses with markers. prmCourse = new SaxGolfUsgaCourse.Params(); prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True; prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.True; prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Priority with markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority with markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); // Non-Priority courses with markers. prmCourse = new SaxGolfUsgaCourse.Params(); prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False; prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.True; prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Non-priority with markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority with markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() }); return group; } //------------------------------------------------------------------- - private AjaxResponse_ReferenceGolfStats.StatGroupData PopulateMarkerStatsData() + private AjaxResponse_Data.StatsGroupData PopulateMarkerStatsData() { - AjaxResponse_ReferenceGolfStats.StatGroupData group = new AjaxResponse_ReferenceGolfStats.StatGroupData() { Caption = "Markers" }; + AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Markers" }; // All markers. SaxGolfUsgaMarker.Params prmMarker = new SaxGolfUsgaMarker.Params(); prmMarker.StatusCat = SaxGolfUsgaMarker.StatusCat.Any; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() }); // Active markers. prmMarker = new SaxGolfUsgaMarker.Params(); prmMarker.StatusCat = SaxGolfUsgaMarker.StatusCat.ActiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() }); // Inctive markers. prmMarker = new SaxGolfUsgaMarker.Params(); prmMarker.StatusCat = SaxGolfUsgaMarker.StatusCat.InactiveOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() }); // Deleted markers. prmMarker = new SaxGolfUsgaMarker.Params(); prmMarker.StatusCat = SaxGolfUsgaMarker.StatusCat.DeletedOnly; - group.Stats.Add(new AjaxResponse_ReferenceGolfStats.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() }); + group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() }); return group; } diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceGolfController-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceGolfController-Ajax.cs index e21be6a..3814089 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceGolfController-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/Reference/ReferenceGolfController-Ajax.cs @@ -464,7 +464,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference // Configure the process. SaxGolfUsgaDataLookup.Config processConfig = new SaxGolfUsgaDataLookup.Config(SessionContext, DbUpdateInfo); - processConfig.Tasks.Add(SaxGolfUsgaDataLookup.Task.CleanseCourseCaptions); + processConfig.Tasks.Add(SaxGolfUsgaDataLookup.Task.CleanseCourses); SaxGolfUsgaDataLookup process = new SaxGolfUsgaDataLookup(processConfig); // Store the process and run. diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/SportController-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/SportController-Ajax.cs index 07e4a67..afe5ff5 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/SportController-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/SportController-Ajax.cs @@ -24,6 +24,8 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers private class SportListData : AjaxResponse_Data.ItemData_Base { public String Name { get; set; } + public String GroupingCode { get; set; } + public String GroupingDesc { get; set; } public String SportIdParent { get; set; } public String SportNameParent { get; set; } public String SpecialityLabelCode { get; set; } @@ -35,6 +37,8 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers private void PopulateSportResponseListData(SaxSport sport, SaxSport parentSport, SportListData data) { data.Id = SysId.ToString(sport.Id); + data.GroupingCode = SportGroupingCodes.GetCodeForType(sport.Grouping); + data.GroupingDesc = SportGroupingCodes.GetDescForType(sport.Grouping); data.SportNameParent = parentSport?.Name ?? null; data.SportIdParent = parentSport?.Id.ToString() ?? null; data.Name = sport.Name; @@ -88,6 +92,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // Item columns. ColumnDfn colId = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.Id); + ColumnDfn colGrouping = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.Grouping); ColumnDfn colParentId = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.SportIdParent); ColumnDfn colParentName = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.ParentSport_Name); ColumnDfn colName = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.Name); @@ -95,7 +100,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers ColumnDfn colStatus = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.Status); List columns = new List() { - colId, colParentId, colParentName, + colId, colGrouping, colParentId, colParentName, colName, colSpecialityLabel, colStatus }; @@ -108,10 +113,13 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers while (resultSet != null && resultSet.HasRows && resultSet.NextRecord()) { NamedValue.Map values = resultSet.GetRecordValues(); + Sax.SportGrouping grouping = (Sax.SportGrouping)values.GetLong(colGrouping.DataName); Sax.SportSpecialityLabel specialityLabel = (Sax.SportSpecialityLabel)values.GetLong(colSpecialityLabel.DataName); SportListData sportData = new SportListData() { Id = values.GetString(colId.DataName), + GroupingCode = SportGroupingCodes.GetCodeForType(grouping), + GroupingDesc = SportGroupingCodes.GetDescForType(grouping), SportIdParent = values.GetString(colParentId.DataName), SportNameParent = values.GetString(colParentName.DataName), Name = values.GetString(colName.DataName), @@ -229,6 +237,8 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers } // Populate item properties. + if (model.SportGroupingCode != null) + sport.Grouping = model.SportGrouping; if (model.SportIdParent != null) sport.SportIdParent = model.SportIdParent.ToSysId(); if (model.SportName != null) diff --git a/SaxoniteCoreWebAdmin/Admin/Models/Model_Sport.cs b/SaxoniteCoreWebAdmin/Admin/Models/Model_Sport.cs index 497c709..325cd04 100644 --- a/SaxoniteCoreWebAdmin/Admin/Models/Model_Sport.cs +++ b/SaxoniteCoreWebAdmin/Admin/Models/Model_Sport.cs @@ -37,8 +37,12 @@ namespace Saxonite.Net.Core.Web.Admin.Models //------------------------------------------------------------------- // Sport properties. public String SportId { get; set; } - public String SportIdParent { get; set; } public String SportName { get; set; } + public String SportGroupingCode { get; set; } + public Sax.SportGrouping SportGrouping { get { return (Sax.SportGrouping)SportGroupingCodes.GetTypeForCode(SportGroupingCode); } } + public String SportIdParent { get; set; } + public String SportIdsParents { get; set; } + public String SportIdsChildren { get; set; } public String SportSpecialityLabelCode { get; set; } public Sax.SportSpecialityLabel SportSpecialityLabel { get { return (Sax.SportSpecialityLabel)SportSpecialityLabelCodes.GetTypeForCode(SportSpecialityLabelCode); } } public String SportStatusCode { get; set; } @@ -54,6 +58,16 @@ namespace Saxonite.Net.Core.Web.Admin.Models using (DisposableCollection disposableItems = new DisposableCollection()) { + // Sport Grouping. + if (SportGroupingCode != null) + { + String controlName = nameof(SportGrouping); + if (StringUtil.IsEmpty(SportGroupingCode)) + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); + else if (SportGrouping <= 0) + responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]); + } + // Parent sport. SysId sportIdParent = SportIdParent.ToSysId(); if (SportIdParent != null && SysId.IsValid(sportIdParent)) @@ -70,11 +84,12 @@ namespace Saxonite.Net.Core.Web.Admin.Models // Sport name. if (SportName != null) { - responseData.SetControlValue(nameof(SportName), SportName); + String controlName = nameof(SportName); + responseData.SetControlValue(controlName, SportName); if (StringUtil.IsEmpty(SportName)) - responseData.SetControlError(nameof(SportName), Localiser["msg.validation.mandatory.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); else if (StringUtil.GetLength(SportName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Sport_Name)) - responseData.SetControlError(nameof(SportName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Sport_Name)]); + responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Sport_Name)]); else { // Check for duplicate name. @@ -85,27 +100,29 @@ namespace Saxonite.Net.Core.Web.Admin.Models prmSport.NameFull = SportName; prmSport.StatusCat = SaxSport.StatusCat.Any; if (ReferenceMgr.GetSportCount(prmSport) > 0) - responseData.SetControlError(nameof(SportName), Localiser["msg.validation.duplicate.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.duplicate.value"]); } } // Sport Speciality Label. if (SportSpecialityLabelCode != null) { + String controlName = nameof(SportSpecialityLabel); if (!StringUtil.IsEmpty(SportSpecialityLabelCode)) { if (SportSpecialityLabel <= 0) - responseData.SetControlError(nameof(SportSpecialityLabel), Localiser["msg.validation.invalid.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]); } } // Sport status. if (SportStatusCode != null) { + String controlName = nameof(SportStatus); if (StringUtil.IsEmpty(SportStatusCode)) - responseData.SetControlError(nameof(SportStatus), Localiser["msg.validation.mandatory.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); else if (!SaxSport.ValidStatuses.Contains(SportStatus)) - responseData.SetControlError(nameof(SportStatus), Localiser["msg.validation.invalid.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]); } } diff --git a/SaxoniteCoreWebAdmin/Admin/Models/Reference/Model_ReferenceBaseball.cs b/SaxoniteCoreWebAdmin/Admin/Models/Reference/Model_ReferenceBaseball.cs new file mode 100644 index 0000000..18d97f6 --- /dev/null +++ b/SaxoniteCoreWebAdmin/Admin/Models/Reference/Model_ReferenceBaseball.cs @@ -0,0 +1,56 @@ +using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Bus; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Utils; +using Saxonite.Base.App; +using Saxonite.Net.Core.Web.Base.App; +using Saxonite.Net.Core.Web.Base.Controllers; +using Saxonite.Net.Core.Web.Base.Models; +using Saxonite.Net.Standard.Base.App; +using Saxonite.Net.Standard.Base.Bus; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Saxonite.Net.Core.Web.Admin.Models.Reference +{ + //======================================================================= + public class Model_ReferenceBaseball : SaxModel_Admin + { + //------------------------------------------------------------------- + // Construction. + public Model_ReferenceBaseball(SaxLocaliser localiser) : + base(localiser) + { + AdditionalFiles_JS.Add("js/ref/sax-ref-baseball.js"); + } + + //------------------------------------------------------------------- + // Reference Baseball list parameters. + public class FilterData + { + } + public FilterData Filter { get; } = new FilterData(); + + //------------------------------------------------------------------- + // Reference Baseball properties. + + //------------------------------------------------------------------- + // Validation. + //------------------------------------------------------------------- + // Reference Baseball. + public bool ValidateReferenceBaseballData(Sacs.Web.Components.SaController.AjaxResponse_Data responseData) + { + // Record disposable items as they are created so all can be disposed when needed. + using (DisposableCollection disposables = new DisposableCollection()) + { + + } + return !responseData.HasControlErrors(); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SaxoniteCoreWebAdmin/Admin/Models/Reference/Model_ReferenceGolf.cs b/SaxoniteCoreWebAdmin/Admin/Models/Reference/Model_ReferenceGolf.cs index e2433e8..6680126 100644 --- a/SaxoniteCoreWebAdmin/Admin/Models/Reference/Model_ReferenceGolf.cs +++ b/SaxoniteCoreWebAdmin/Admin/Models/Reference/Model_ReferenceGolf.cs @@ -23,7 +23,7 @@ namespace Saxonite.Net.Core.Web.Admin.Models.Reference public Model_ReferenceGolf(SaxLocaliser localiser) : base(localiser) { - AdditionalFiles_JS.Add("js/sax-ref-golf.js"); + AdditionalFiles_JS.Add("js/ref/sax-ref-golf.js"); } //------------------------------------------------------------------- @@ -52,7 +52,7 @@ namespace Saxonite.Net.Core.Web.Admin.Models.Reference public bool ValidateReferenceGolfData(Sacs.Web.Components.SaController.AjaxResponse_Data responseData) { // Record disposable items as they are created so all can be disposed when needed. - using (DisposableCollection disposableItems = new DisposableCollection()) + using (DisposableCollection disposables = new DisposableCollection()) { } return !responseData.HasControlErrors(); diff --git a/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx b/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx index 925e71f..54ffbae 100644 --- a/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx +++ b/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Baseball + Contact Method @@ -162,6 +165,9 @@ Organisations + + Reference - Baseball + Reference - Golf @@ -375,6 +381,15 @@ Gender + + Grouped sports + + + Grouping + + + Groups + Header row diff --git a/SaxoniteCoreWebAdmin/SaxoniteCoreWebAdmin.csproj b/SaxoniteCoreWebAdmin/SaxoniteCoreWebAdmin.csproj index 56bb984..8a66a10 100644 --- a/SaxoniteCoreWebAdmin/SaxoniteCoreWebAdmin.csproj +++ b/SaxoniteCoreWebAdmin/SaxoniteCoreWebAdmin.csproj @@ -10,7 +10,7 @@ - + @@ -36,7 +36,7 @@ true PreserveNewest - + true PreserveNewest diff --git a/SaxoniteCoreWebAdmin/Views/Common/Template-Icons.cshtml b/SaxoniteCoreWebAdmin/Views/Common/Template-Icons.cshtml new file mode 100644 index 0000000..60bbf0d --- /dev/null +++ b/SaxoniteCoreWebAdmin/Views/Common/Template-Icons.cshtml @@ -0,0 +1,10 @@ +@model SaxModel_Admin +@inject SaxLocaliser Localiser + +@* Icons. *@ +
+ + Active + Inactive + Deleted +
diff --git a/SaxoniteCoreWebAdmin/Views/Reference/Baseball/Index.cshtml b/SaxoniteCoreWebAdmin/Views/Reference/Baseball/Index.cshtml new file mode 100644 index 0000000..c555f90 --- /dev/null +++ b/SaxoniteCoreWebAdmin/Views/Reference/Baseball/Index.cshtml @@ -0,0 +1,73 @@ +@model Model_ReferenceBaseball +@inject SaxLocaliser Localiser +@{ + /* Reference - Baseball - Index */ + ViewData["Title"] = "Reference - Baseball"; +} + +
+ + + +
+
+
@Localiser["caption.reference.baseball"]
+
+
@(Localiser[
+
+
+ @using (@Html.BeginForm(FormMethod.Post, new { @id = "frmRefBaseballFilter", @class = "sax-form", @onSubmit = "return false;" })) + { + @* +
+
+
@Localiser["label.options"]
+
+
+
+
+ *@ + } +
+ + @* Reference - Baseball - Stats *@ +
+ +
+
@Localiser["label.statictics"]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + @* Templates. *@ + + +
diff --git a/SaxoniteCoreWebAdmin/Views/Reference/Golf/Index.cshtml b/SaxoniteCoreWebAdmin/Views/Reference/Golf/Index.cshtml index 6442e75..ca66289 100644 --- a/SaxoniteCoreWebAdmin/Views/Reference/Golf/Index.cshtml +++ b/SaxoniteCoreWebAdmin/Views/Reference/Golf/Index.cshtml @@ -285,12 +285,7 @@ } - @* Icons. *@ -
- - Active - Inactive - Deleted -
+ @* Templates. *@ + diff --git a/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml b/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml index bf3e7cb..8797c34 100644 --- a/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml +++ b/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml @@ -136,6 +136,8 @@ diff --git a/SaxoniteCoreWebAdmin/Views/Sport/Panel-SportDialog.cshtml b/SaxoniteCoreWebAdmin/Views/Sport/Panel-SportDialog.cshtml index 95a7a2c..7210e92 100644 --- a/SaxoniteCoreWebAdmin/Views/Sport/Panel-SportDialog.cshtml +++ b/SaxoniteCoreWebAdmin/Views/Sport/Panel-SportDialog.cshtml @@ -42,7 +42,24 @@ - @* Sport Parent *@ + @* Sport Grouping *@ +
+
+
+
+ +
+
+
+
+ @Html.DropDownListFor(model => model.SportGroupingCode, Model.SportGroupingCodesForSelect, new { @id = "cbSportGrouping", @class = "SportGrouping sax-select" }) +
+
+
+
+
+ + @* Banner Sport *@
@@ -62,6 +79,26 @@
+ @* Child Sports *@ +
+
+
+
+ +
+
+
+
+ @Html.HiddenFor(model => model.SportIdsChildren, new { @id = "ifSportIdsChildren", @class = "SportIdsChildren" }) +
+
@(Localiser[
+
+
+
+
+
+
+ @* Sport Speciality Label *@
diff --git a/SaxoniteCoreWebAdmin/wwwroot/css/sax-data.css b/SaxoniteCoreWebAdmin/wwwroot/css/sax-data.css index f7d82e0..921ac55 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/css/sax-data.css +++ b/SaxoniteCoreWebAdmin/wwwroot/css/sax-data.css @@ -36,7 +36,7 @@ font-weight: bold; } -.sax-panel-filter .sax-header ul.nav.sax-burger +.sax-panel-filter ul.nav.sax-burger { margin-top: 2px; } @@ -62,7 +62,7 @@ .sax-panel-filter .sax-content .sax-label { - padding-top: 2px; + padding-top: 6px; padding-right: 12px; text-align: right; } @@ -113,19 +113,19 @@ /* Panel header - Burger */ -.sax-header ul.nav.sax-burger +ul.nav.sax-burger { margin: 0; } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu +ul.nav.sax-burger ul.sax-dropdown-menu { padding: 4px 8px 4px 4px; border-radius: 2px 2px 8px 4px; box-shadow: 0 0 8px 2px #80808080; } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item { margin: 2px 4px 2px 0; padding: 2px 4px 2px 30px; @@ -133,109 +133,109 @@ background-position: left center; } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-refresh +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-refresh { background-image: url('../img/action/refresh24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-info +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-info { background-image: url('../img/action/info24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-add +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-add { background-image: url('../img/action/add24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-edit +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-edit { background-image: url('../img/action/edit24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-remove +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-remove { background-image: url('../img/action/delete24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-experience +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-experience { background-image: url('../img/action/trophy24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-user +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-user { background-image: url('../img/action/user24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-users +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-users { background-image: url('../img/action/users24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-mail +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-mail { background-image: url('../img/action/mail24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-location +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-location { background-image: url('../img/action/location-24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-image +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-image { background-image: url('../img/action/image-24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-process +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-process { background-image: url('../img/action/process24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-upload +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-upload { background-image: url('../img/action/upload24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-download +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-download { background-image: url('../img/action/download24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-network +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-network { background-image: url('../img/action/network-24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-close +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-close { background-image: url('../img/action/prev24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-itemlock +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-itemlock { background-image: url('../img/action/lock24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-unlock +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item.sax-unlock { background-image: url('../img/action/unlock24.png'); } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item:hover +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item:hover { background-color: #f8f8f8; box-shadow: none; } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item .sax-label +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item .sax-label { margin: 0; padding: 0 0 0 4px; } -.sax-header ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item:hover .sax-label +ul.nav.sax-burger ul.sax-dropdown-menu li.sax-action.sax-dropdown-item:hover .sax-label { background-color: #f8f8f8; box-shadow: 0 0 2px 1px #80808080; @@ -353,7 +353,7 @@ table.sax-item-list tbody td font-weight: bold; } -.sax-panel-item > .sax-header ul.nav.sax-burger +.sax-panel-item > ul.nav.sax-burger { margin: 0; } diff --git a/SaxoniteCoreWebAdmin/wwwroot/css/sax-form.css b/SaxoniteCoreWebAdmin/wwwroot/css/sax-form.css index 632bcdf..e58b2da 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/css/sax-form.css +++ b/SaxoniteCoreWebAdmin/wwwroot/css/sax-form.css @@ -140,7 +140,7 @@ .sax-form .sax-form-control .sax-label { - margin: 0 0 8px 0; + margin: 4px 0 4px 0; font-size: 1rem; line-height: 1.25; } @@ -183,9 +183,9 @@ .sax-form .sax-input:read-only, .sax-form .sax-textarea:read-only, .sax-form .sax-select:disabled { - color: #202020; + color: #404040; opacity: 1; - background-color: #f8f8f8; + background-color: #f0f0f0; } .sax-form .sax-form-control.sax-error .sax-input, .sax-form .sax-form-control.sax-error .sax-textarea, .sax-form .sax-form-control.sax-error .sax-select diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/ref/sax-ref-baseball.js b/SaxoniteCoreWebAdmin/wwwroot/js/ref/sax-ref-baseball.js new file mode 100644 index 0000000..a325328 --- /dev/null +++ b/SaxoniteCoreWebAdmin/wwwroot/js/ref/sax-ref-baseball.js @@ -0,0 +1,91 @@ +/* + * Admin - Reference - Baseball page scripts. + */ + +(function (win, doc, undef) +{ + "use strict"; + let rb = sax.refBaseball = sax.refBaseball || { ajax: {}, data: {}, fn: {}, $pnl: {}, $frm: {}, $dlg: {} }; + rb.attr_id = 'sax-id'; + rb.class_sel = 'sax-sel'; + + //-------------------------------------------------------------- + /* Reference - Baseball - Stats. */ + rb.fn.refreshStats = function (delay) + { + rb.ajax.baseballStats = rb.ajax.baseballStats || { url: sax.url.base + 'Reference/Baseball/Ajax/GetStats', formId: rb.$frm.filter.prop('id'), callbackFn: rb.fn.doRefreshStats }; + sax.doAjaxRequest(rb.ajax.baseballStats, delay || 50); + } + rb.fn.doRefreshStats = function (response) + { + if (!response.success) return; + let $msgs = $('.sax-panel-messages', rb.$pnl.stats).empty(); + let $list = $('.sax-panel-item-list', rb.$pnl.stats).empty(); + for (let groupIdx = 0; groupIdx < (response.groups || []).length; groupIdx++) + { + let group = response.groups[groupIdx]; + $list.append(rb.fn.populateStatGroup(rb.fn.getStatGroupTemplate(), group.caption)); + for (let statIdx = 0; statIdx < (group.stats || []).length; statIdx++) + { + let stat = group.stats[statIdx]; + if (stat.value > 0) $list.append(rb.fn.populateStat(rb.fn.getStatTemplate(), stat.caption, stat.value)); + } + } + } + rb.fn.populateStatGroup = function ($item, caption) + { + $('.GroupCaption', $item).text(caption); + return $item; + } + rb.fn.getStatGroupTemplate = function () + { + return $('.sax-panel-item-template .BaseballStatGroup', rb.$pnl.stats).clone(); + } + rb.fn.populateStat = function ($item, caption, value) + { + $('.StatCaption', $item).text(caption); + $('.StatValue', $item).text(value); + return $item; + } + rb.fn.getStatTemplate = function () + { + return $('.sax-panel-item-template .BaseballStat', rb.$pnl.stats).clone(); + } + + //-------------------------------------------------------------- + // Utilities. + rb.fn.getMenuOption = function ($opt, lbl, fn, cls) + { + return $opt.find('div.sax-label').text(lbl).end().on('click', fn).addClass(cls); + } + rb.fn.getTickIcon = function () + { + return $('.sax-panel-item-template img.sax-tick', rb.$pnl.baseball).clone(); + } + rb.fn.getCrossIcon = function () + { + return $('.sax-panel-item-template img.sax-cross', rb.$pnl.baseball).clone(); + } + rb.fn.getStatusIcon = function (stat) + { + return $('.sax-panel-item-template img.sax-status-' + stat, rb.$pnl.baseball).clone(); + } + + //-------------------------------------------------------------- + $(function () + { + rb.$pnl.baseball = $('.sax-panel.Baseball'); + rb.$pnl.filter = $('.sax-panel-filter', rb.$pnl.baseball); + $('.sax-results-refresh', rb.$pnl.filter).on('click', rb.fn.refreshStats); + rb.$frm.filter = $('#frmRefBaseballFilter', rb.$pnl.filter); + + // Stats. + rb.$pnl.stats = $('.sax-panel-info.BaseballStats', rb.$pnl.baseball); + setTimeout(function () { rb.fn.refreshStats(); }, 250); + + }); + + //-------------------------------------------------------------- +}(window, window.document)); + +/* The End */ \ No newline at end of file diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-ref-golf.js b/SaxoniteCoreWebAdmin/wwwroot/js/ref/sax-ref-golf.js similarity index 99% rename from SaxoniteCoreWebAdmin/wwwroot/js/sax-ref-golf.js rename to SaxoniteCoreWebAdmin/wwwroot/js/ref/sax-ref-golf.js index 76df989..c85d6a4 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-ref-golf.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/ref/sax-ref-golf.js @@ -1,5 +1,5 @@ /* - * Admin - User page scripts. + * Admin - Reference - Golf page scripts. */ (function (win, doc, undef) diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-org-mbr.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-org-mbr.js index 95ac37e..b60b137 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-org-mbr.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-org-mbr.js @@ -56,11 +56,11 @@ if (!item) return; $item.prop('id', om.itemIdPrefix + item.id); $('.UserEmailAddress', $item).text(item.emailAddress); - $('.UserStatusDesc', $item).text(item.userStatusDesc).addClass('sax-status-' + (item.userStatusCode || '').toLowerCase()); + $('.UserStatusDesc', $item).text(item.userStatusDesc).removeClass(function (idx, name) { return (name.match(/(^|\s)sax-status-\S+/g) || []).join(' '); }).addClass('sax-status-' + (item.userStatusCode || '').toLowerCase()); $('.UserStatus', $item).toggle(!item.userActive); $('.UserDisplayName', $item).text(item.displayName); $('.MemberRoleCount .RoleCount', $item).text(item.roleCount); - $('.StatusDesc', $item).text(item.statusDesc).addClass('sax-status-' + item.statusCode.toLowerCase()); + $('.StatusDesc', $item).text(item.statusDesc).removeClass(function (idx, name) { return (name.match(/(^|\s)sax-status-\S+/g) || []).join(' '); }).addClass('sax-status-' + item.statusCode.toLowerCase()); $('.sax-caption .sax-action').toggleClass('sax-action', !item.deleted); let $mnu = $('ul.sax-dropdown-menu', $item).empty(); if (!item.deleted) diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-org.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-org.js index 1220b54..5ba00c2 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-org.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-org.js @@ -65,7 +65,7 @@ $('.OrganisationSport', $item).text(item.sportName); $('.OrganisationRegion', $item).text(item.regionPrimary.name); $('.OrganisationMemberCount', $item).on('click', function () { op.onClickMemberCount(item.id); }).find('.MemberCount').text(item.memberCount); - $('.StatusDesc', $item).text(item.statusDesc).addClass('sax-status-' + item.statusCode.toLowerCase()); + $('.StatusDesc', $item).text(item.statusDesc).removeClass(function (idx, name) { return (name.match(/(^|\s)sax-status-\S+/g) || []).join(' '); }).addClass('sax-status-' + item.statusCode.toLowerCase()); $('.sax-caption .sax-action').toggleClass('sax-action', !item.deleted); let $mnu = $('ul.sax-dropdown-menu', $item).empty(); if (!item.deleted) diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-rgn.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-rgn.js index 1d2b4ad..e140224 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-rgn.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-rgn.js @@ -55,7 +55,7 @@ $('.RegionCountryIso2Code', $item).text(item.countryIso2Code); $('.RegionTypeDesc', $item).text(item.regionTypeDesc); $('.RegionParentName', $item).text(item.parentName); - $('.RegionStatusDesc', $item).text(item.statusDesc).addClass('sax-status-' + item.statusCode.toLowerCase()); + $('.RegionStatusDesc', $item).text(item.statusDesc).removeClass(function (idx, name) { return (name.match(/(^|\s)sax-status-\S+/g) || []).join(' '); }).addClass('sax-status-' + item.statusCode.toLowerCase()); $('.sax-caption .sax-action, .sax-actions .sax-action.sax-item-update', $item).off('click').on('click', function () { sax.updateItem(item.id) }) $item.off('dblclick').on('dblclick', function () { sax.updateItem(item.id) }) $('.sax-panel-results .sax-panel-messages').hide().empty(); diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-sport.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-sport.js index 31f810f..58a32a4 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-sport.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-sport.js @@ -56,11 +56,12 @@ if (!item) return; $item.prop('id', sax.itemIdPrefix + item.id); $('.SportName', $item).text(item.name); + $('.SportGrouping', $item).text(item.groupingDesc); $('.SportNameParent', $item).text(item.sportNameParent); $('.SportParent', $item).toggle(!!item.sportNameParent); $('.SportSpecialityLabel', $item).text(item.specialityLabelDesc); $('.SportSpeciality', $item).toggle(!!item.specialityLabelCode); - $('.StatusDesc', $item).text(item.statusDesc).addClass('sax-status-' + item.statusCode.toLowerCase()); + $('.StatusDesc', $item).text(item.statusDesc).removeClass(function (idx, name) { return (name.match(/(^|\s)sax-status-\S+/g) || []).join(' '); }).addClass('sax-status-' + item.statusCode.toLowerCase()); $('.sax-caption .sax-action').toggleClass('sax-action', !item.deleted); let $mnu = $('ul.sax-dropdown-menu', $item).empty(); if (!item.deleted) @@ -131,6 +132,7 @@ if (!response.success) return; let item = response.sport; $('.SportId', frm).val(item.id); + $('.SportGrouping', frm).val(item.groupingCode); $('.SportIdParent', frm).val(item.sportIdParent); $('.SportNameParent', frm).val(item.sportNameParent); $('.SportName', frm).val(item.name); diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-spt-rpt.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-spt-rpt.js index b5d30ab..9012f51 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-spt-rpt.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-spt-rpt.js @@ -55,7 +55,7 @@ $('.UserReportTitle', $item).text(item.title); $('.UserDisplayName', $item).text(item.userDisplayName); $('.UserReportRaisedOnDisp', $item).text(item.recordedOnDisp); - $('.StatusDesc', $item).text(item.statusDesc).addClass('sax-status-' + item.statusCode.toLowerCase()); + $('.StatusDesc', $item).text(item.statusDesc).removeClass(function (idx, name) { return (name.match(/(^|\s)sax-status-\S+/g) || []).join(' '); }).addClass('sax-status-' + item.statusCode.toLowerCase()); $('.sax-caption .sax-action',$item).toggleClass('sax-action', !item.deleted); let $mnu = $('ul.sax-dropdown-menu', $item).empty(); if (!item.deleted) diff --git a/SaxoniteCoreWebAdmin/wwwroot/js/sax-usr.js b/SaxoniteCoreWebAdmin/wwwroot/js/sax-usr.js index a01bfe7..2387b76 100644 --- a/SaxoniteCoreWebAdmin/wwwroot/js/sax-usr.js +++ b/SaxoniteCoreWebAdmin/wwwroot/js/sax-usr.js @@ -71,7 +71,7 @@ $('.UserLastOnlineLogin', $item).toggle(!!item.lastOnlineLoginAt); $('.UserLastAdminLoginAt', $item).text(item.lastAdminLoginAt); $('.UserLastAdminLogin', $item).toggle(!!item.lastAdminLoginAt); - $('.StatusDesc', $item).text(item.statusDesc).addClass('sax-status-' + item.statusCode.toLowerCase()); + $('.StatusDesc', $item).text(item.statusDesc).removeClass(function (idx, name) { return (name.match(/(^|\s)sax-status-\S+/g) || []).join(' '); }).addClass('sax-status-' + item.statusCode.toLowerCase()); $('.sax-caption .sax-action').toggleClass('sax-action', !item.deleted); let $mnu = $('ul.sax-dropdown-menu', $item); if (!item.deleted) diff --git a/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx b/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx index 27b8b18..7f50964 100644 --- a/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx +++ b/SaxoniteCoreWebOnline/Localisation/SaxOnlineProperties.resx @@ -273,6 +273,9 @@ My Account + + Actions + Activate @@ -345,6 +348,9 @@ Contacts + + Copy + Country @@ -396,6 +402,9 @@ Email address + + Ends + Events @@ -423,6 +432,9 @@ Feedback + + Finishes + First @@ -645,6 +657,9 @@ Available sports + + Starts + Strength @@ -675,6 +690,9 @@ Type + + Until + Update diff --git a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs b/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs index 912b655..8b14100 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/AccountController-Ajax-Contact.cs @@ -61,9 +61,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers data.About = userAccount.About; data.Gender = (byte)userAccount.Gender; data.GenderCaption = Localiser.GetGenderCaption(userAccount.Gender); - data.DobDay = (byte)userAccount.DateOfBirthDay; - data.DobMonth = (byte)userAccount.DateOfBirthMonth; - data.DobYear = (short)userAccount.DateOfBirthYear; + data.DobDay = (byte)(userAccount.DateOfBirthDay ?? 0); + data.DobMonth = (byte)(userAccount.DateOfBirthMonth ?? 0); + data.DobYear = (short)(userAccount.DateOfBirthYear ?? 0); if (ItemDataMgr.ItemHasActiveImage(userAccount.GetItemId(), Sax.ImageType.Avatar)) data.HasImage = true; // Regions. @@ -205,18 +205,28 @@ namespace Saxonite.Net.Core.Web.Online.Controllers imageData = fileStream.ToArray(); } + // Validate content type. + if (StringUtil.IsEmpty(file.ContentType) || !SaxItemImage.GetValidContentTypes(Sax.DataItemType.UserAccount).ContainsCI(file.ContentType)) + return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.upload.image.invalid.content.type"])); + Sarand.Net.Standard.Base.Core.Sacs.MimeType mimeTypeExpected = SacsContentTypeHelper.GetMimeTypeFromContentType(file.ContentType); + // Validate the image. - ImageUtils.ImageConfig imageConfig = ImageUtils.VerifyImageData(imageData); + ImageUtils.ImageConfig imageConfig = null; + if (mimeTypeExpected == Sarand.Net.Standard.Base.Core.Sacs.MimeType.Svg) + imageConfig = ImageUtils.VerifySvgImageData(imageData); + else + imageConfig = ImageUtils.VerifyImageData(imageData); if (!imageConfig.ValidImage) return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.upload.image.invalid"])); // Validate mime type. if (!SaxItemImage.GetValidMimeTypes(Sax.DataItemType.UserAccount).Contains(imageConfig.MimeType)) return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.upload.image.invalid.mime"])); - - // Validate content type. - if (StringUtil.IsEmpty(file.ContentType) || !SaxItemImage.GetValidContentTypes(Sax.DataItemType.UserAccount).ContainsCI(file.ContentType)) - return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.upload.image.invalid.content.type"])); + if (imageConfig.MimeType != mimeTypeExpected) + { + SaLogger.Warn($"{SysUtil.Fn} Image upload - inconsistent Mime. Filename: {file.FileName}. Mime: {imageConfig.MimeType}. Expected Mime: {mimeTypeExpected}."); + return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid"])); + } // Resize the image if required. if (!ImageUtils.ConstrainImage(imageConfig, Sax.Config.User.Image.WidthMax, Sax.Config.User.Image.HeightMax)) diff --git a/SaxoniteCoreWebOnline/Online/Controllers/ArticleController-Ajax.cs b/SaxoniteCoreWebOnline/Online/Controllers/ArticleController-Ajax.cs index 4b2ae74..97a8659 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/ArticleController-Ajax.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/ArticleController-Ajax.cs @@ -444,18 +444,28 @@ namespace Saxonite.Net.Core.Web.Online.Controllers imageData = fileStream.ToArray(); } + // Validate content type. + if (StringUtil.IsEmpty(file.ContentType) || !SaxItemImage.GetValidContentTypes(Sax.DataItemType.Article).ContainsCI(file.ContentType)) + return Json(responseData.SetControlError("ArticleImage", Localiser["msg.upload.image.invalid.content.type"])); + Sarand.Net.Standard.Base.Core.Sacs.MimeType mimeTypeExpected = SacsContentTypeHelper.GetMimeTypeFromContentType(file.ContentType); + // Validate the image. - ImageUtils.ImageConfig imageConfig = ImageUtils.VerifyImageData(imageData); + ImageUtils.ImageConfig imageConfig = null; + if (mimeTypeExpected == Sarand.Net.Standard.Base.Core.Sacs.MimeType.Svg) + imageConfig = ImageUtils.VerifySvgImageData(imageData); + else + imageConfig = ImageUtils.VerifyImageData(imageData); if (!imageConfig.ValidImage) return Json(responseData.SetControlError("ArticleImage", Localiser["msg.upload.image.invalid"])); // Validate mime type. if (!SaxItemImage.GetValidMimeTypes(Sax.DataItemType.Article).Contains(imageConfig.MimeType)) return Json(responseData.SetControlError("ArticleImage", Localiser["msg.upload.image.invalid.mime"])); - - // Validate content type. - if (StringUtil.IsEmpty(file.ContentType) || !SaxItemImage.GetValidContentTypes(Sax.DataItemType.Article).ContainsCI(file.ContentType)) - return Json(responseData.SetControlError("ArticleImage", Localiser["msg.upload.image.invalid.content.type"])); + if (imageConfig.MimeType != mimeTypeExpected) + { + SaLogger.Warn($"{SysUtil.Fn} Image upload - inconsistent Mime. Filename: {file.FileName}. Mime: {imageConfig.MimeType}. Expected Mime: {mimeTypeExpected}."); + return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid"])); + } // Resize the image if required. if (!ImageUtils.ConstrainImage(imageConfig, Sax.Config.Articles.Images.WidthMax, Sax.Config.Articles.Images.HeightMax)) diff --git a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Events.cs b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Events.cs index 1d890d8..3705037 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Events.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController-Ajax-Events.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Diagnostics; using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Bus; using Sarand.Net.Standard.Base.Core; @@ -23,12 +24,14 @@ namespace Saxonite.Net.Core.Web.Online.Controllers // Organisation Event data. private class EventListData : AjaxResponse_Data.ItemData_Base { - public String EventDateFmt { get; set; } - public String EventTimeFmt { get; set; } + public String EventAtDateFmt { get; set; } + public String EventAtTimeFmt { get; set; } + public String EventToDateFmt { get; set; } + public String EventToTimeFmt { get; set; } + public String Duration { get; set; } public String TypeCode { get; set; } public String TypeDesc { get; set; } public String Summary { get; set; } - public String Details { get; set; } public String SportCaptionPrimary { get; set; } public String RegionCaptionCountry { get; set; } public String PublishedOnFmt { get; set; } @@ -36,9 +39,13 @@ namespace Saxonite.Net.Core.Web.Online.Controllers } private class EventItemData : EventListData { - public String EventOn_Calendar { get; set; } - public String EventOn_YYYYMMDD { get; set; } + public String EventAt_Calendar { get; set; } + public String EventAt_YYYYMMDD { get; set; } public String EventAt_HHMM { get; set; } + public String EventTo_Calendar { get; set; } + public String EventTo_YYYYMMDD { get; set; } + public String EventTo_HHMM { get; set; } + public String Details { get; set; } public String SportIdPrimary { get; set; } public String RegionIdCountry { get; set; } public String PublishedOn_YYYYMMDD { get; set; } @@ -47,30 +54,51 @@ namespace Saxonite.Net.Core.Web.Online.Controllers private void PopulateEventResponseListData(Model_Organisation_Events model, SaxOrganisationEvent organisationEvent, EventListData data) { data.Id = model.EncryptId(organisationEvent.Id); - data.EventDateFmt = Localiser.FormatDate(organisationEvent.EventAt); - data.EventTimeFmt = DateUtil.Format(organisationEvent.EventAt, "HH:mm"); + // 'At' date/time. + data.EventAtDateFmt = Localiser.FormatDate(organisationEvent.EventAt); + if (organisationEvent.HasValidEventAtTime()) + data.EventAtTimeFmt = DateUtil.Format(organisationEvent.EventAt, "HH:mm"); + // 'To' date/time. + data.EventToDateFmt = Localiser.FormatDate(organisationEvent.EventTo); + if (organisationEvent.HasValidEventToTime()) + data.EventToTimeFmt = DateUtil.Format(organisationEvent.EventTo, "HH:mm"); + // Event properties. + if (DateUtil.IsValid(organisationEvent.EventTo) && organisationEvent.EventTo > organisationEvent.EventAt) + data.Duration = DateUtil.FormatNumberOfSeconds(((DateTime)organisationEvent.EventTo - organisationEvent.EventAt).TotalSeconds); data.TypeCode = EventTypeCodes.GetCodeForType(organisationEvent.EventType); data.TypeDesc = Localiser.GetEventTypeCaption(organisationEvent.EventType); data.Summary = organisationEvent.Summary; - data.Details = organisationEvent.Details; data.SportCaptionPrimary = model.GetSportCaption(organisationEvent.SportIdPrimary); data.RegionCaptionCountry = model.GetRegionCaption(organisationEvent.RegionIdCountry); data.CreatedOnFmt = Localiser.FormatDate(organisationEvent.CreateStamp.On); - data.PublishedOnFmt = Localiser.FormatDate(organisationEvent.PublishedAt); - data.ExpiresOnFmt = Localiser.FormatDate(organisationEvent.ExpiresAt); + if (DateUtil.IsValid(organisationEvent.PublishedAt)) + data.PublishedOnFmt = Localiser.FormatDate(organisationEvent.PublishedAt); + if (DateUtil.IsValid(organisationEvent.ExpiresAt)) + data.ExpiresOnFmt = Localiser.FormatDate(organisationEvent.ExpiresAt); data.StatusCode = organisationEvent.StatusCode; data.StatusDesc = organisationEvent.StatusDesc; } private void PopulateEventResponseItemData(Model_Organisation_Events model, SaxOrganisationEvent organisationEvent, EventItemData data) { PopulateEventResponseListData(model, organisationEvent, data as EventListData); - data.EventOn_Calendar = model.FormatDateForForm(organisationEvent.EventAt); - data.EventOn_YYYYMMDD = DateUtil.Format(organisationEvent.EventAt, "yyyyMMdd"); - data.EventAt_HHMM = DateUtil.Format(organisationEvent.EventAt, "HH:mm"); + // 'At' date/time. + data.EventAt_Calendar = model.FormatDateForForm(organisationEvent.EventAt); + data.EventAt_YYYYMMDD = DateUtil.Format(organisationEvent.EventAt, "yyyyMMdd"); + if (organisationEvent.HasValidEventAtTime()) + data.EventAt_HHMM = DateUtil.Format(organisationEvent.EventAt, "HH:mm"); + // 'To' date/time. + data.EventTo_Calendar = model.FormatDateForForm(organisationEvent.EventTo); + data.EventTo_YYYYMMDD = DateUtil.Format(organisationEvent.EventTo, "yyyyMMdd"); + if (organisationEvent.HasValidEventToTime()) + data.EventTo_HHMM = DateUtil.Format(organisationEvent.EventTo, "HH:mm"); + // Event properties. + data.Details = organisationEvent.Details; data.RegionIdCountry = model.GetEncryptedRegionId(organisationEvent.RegionIdCountry); data.SportIdPrimary = model.GetEncryptedSportId(organisationEvent.SportIdPrimary); - data.PublishedOn_YYYYMMDD = DateUtil.Format(organisationEvent.PublishedAt, "yyyyMMdd"); - data.ExpiresOn_YYYYMMDD = DateUtil.Format(organisationEvent.ExpiresAt, "yyyyMMdd"); + if (DateUtil.IsValid(organisationEvent.PublishedAt)) + data.PublishedOn_YYYYMMDD = DateUtil.Format(organisationEvent.PublishedAt, "yyyyMMdd"); + if (DateUtil.IsValid(organisationEvent.ExpiresAt)) + data.ExpiresOn_YYYYMMDD = DateUtil.Format(organisationEvent.ExpiresAt, "yyyyMMdd"); } //------------------------------------------------------------------- @@ -101,6 +129,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers public OrganisationData Organisation { get; } = new OrganisationData(); // Reference data. public List EventTypes { get; } = new List(); + public String EventTypeDefault { get; set; } } //------------------------------------------------------------------- [HttpPost] @@ -140,6 +169,8 @@ namespace Saxonite.Net.Core.Web.Online.Controllers // Reference data - organisationEvent types. foreach (TypeCodeDesc eventType in EventTypeCodes) responseData.EventTypes.Add(eventType.Code, Localiser.GetEventTypeCaption((Sax.EventType)eventType.Type)); + // ToDo: Organisation default Event Type. + responseData.EventTypeDefault = EventTypeCodes.GetCodeForType(Sax.EventType.Playing); // User organisation. SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params(); @@ -170,17 +201,34 @@ namespace Saxonite.Net.Core.Web.Online.Controllers SaxOrganisationEvent.Params prmEvent = new SaxOrganisationEvent.Params(); prmEvent.UserAccountIdsIncluded.Add(userAccountId); prmEvent.OrganisationIdsIncluded.Add(organisationId); + switch (model.Filter.Period.PeriodType) + { + case Model_Organisation_Events.PeriodType.FromThisMonth: + prmEvent.EventFrom = DateUtil.StartOfMonth(DateTime.Today); + break; + case Model_Organisation_Events.PeriodType.FromLastMonth: + prmEvent.EventFrom = DateUtil.StartOfMonth(DateUtil.IncrementMonth(DateTime.Today, -1)); + break; + case Model_Organisation_Events.PeriodType.FromNextMonth: + prmEvent.EventFrom = DateUtil.StartOfMonth(DateUtil.IncrementMonth(DateTime.Today, 1)); + break; + case Model_Organisation_Events.PeriodType.FromThisWeek: + default: + prmEvent.EventFrom = DateUtil.StartOfWorkingWeek(DateTime.Today); + break; + } prmEvent.EventFilter = model.Filter.Event; prmEvent.StatusCat = SaxOrganisationEvent.StatusCat.NotDeleted; + prmEvent.SortColumns.Add(ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventAt_DateTime)); model.Paging.ItemTotal = (ulong)ActivityMgr.GetOrganisationEventCount(prmEvent); model.PopulatePagingTo(prmEvent.ResultsPaging); // Item columns. ColumnDfn colId = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Id); ColumnDfn colEventAt = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventAt_DateTime); + ColumnDfn colEventTo = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventTo_DateTime); ColumnDfn colEventTypeCode = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventTypeCode); ColumnDfn colSummary = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Summary); - ColumnDfn colDetails = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Details); ColumnDfn colRegionId = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.RegionIdCountry); ColumnDfn colRegionName = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Region_Name); ColumnDfn colSportId = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.SportIdPrimary); @@ -191,7 +239,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers ColumnDfn colCreatedOn = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.CreateOn_Date); List columns = new List() { - colId, colEventAt, colEventTypeCode, colSummary, colDetails, + colId, colEventAt, colEventTo, colEventTypeCode, colSummary, colRegionId, colRegionName, colSportId, colSportName, colPublishedOn, colExpiresOn, colStatus, colCreatedOn @@ -207,15 +255,15 @@ namespace Saxonite.Net.Core.Web.Online.Controllers while (resultSet != null && resultSet.HasRows && resultSet.NextRecord()) { NamedValue.Map values = resultSet.GetRecordValues(); + DateTime eventAt = values.GetDateTime(colEventAt.DataName); + DateTime? eventTo = values.GetDateTime(colEventTo.DataName); EventListData eventData = new EventListData() { Id = model.EncryptId(new SysId(values.GetLong(colId.DataName))), - EventDateFmt = Localiser.FormatDate(values.GetDateTime(colEventAt.DataName)), - EventTimeFmt = DateUtil.Format(values.GetDateTime(colEventAt.DataName), "HH:mm"), + EventAtDateFmt = Localiser.FormatDate(values.GetDateTime(colEventAt.DataName)), TypeCode = values.GetString(colEventTypeCode.DataName), TypeDesc = Localiser.GetEventTypeCaption((Sax.EventType)EventTypeCodes.GetTypeForCode(values.GetString(colEventTypeCode.DataName))), Summary = ActivityMgr.GetOrganisationEventDataValue(colSummary, values).AsString(), - Details = ActivityMgr.GetOrganisationEventDataValue(colDetails, values).AsString(), RegionCaptionCountry = model.GetRegionCaption(values.GetString(colRegionId.DataName).ToSysId()), SportCaptionPrimary = model.GetSportCaption(values.GetString(colSportId.DataName).ToSysId()), CreatedOnFmt = Localiser.FormatDate(values.GetDateTime(colCreatedOn.DataName)), @@ -224,6 +272,14 @@ namespace Saxonite.Net.Core.Web.Online.Controllers StatusCode = values.GetString(colStatus.DataName), StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName)) }; + if (SaxOrganisationEvent.HasValidEventTime(eventAt)) + eventData.EventAtTimeFmt = DateUtil.Format(eventAt, "HH:mm"); + if (DateUtil.IsValid(eventTo) && eventAt.Date != ((DateTime)eventTo).Date) + eventData.EventToDateFmt = Localiser.FormatDate(eventTo); + if (SaxOrganisationEvent.HasValidEventTime(eventTo)) + eventData.EventToTimeFmt = DateUtil.Format(eventTo, "HH:mm"); + if (DateUtil.IsValid(eventTo) && eventTo > eventAt) + eventData.EventAtTimeFmt = DateUtil.FormatNumberOfSeconds(((DateTime)eventTo - eventAt).TotalSeconds); responseData.Events.Add(eventData); } } @@ -254,7 +310,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers public IActionResult Ajax_GetEvent(Model_Organisation_Events model) { String fn = GetType().Name + ".Ajax_GetEvent"; - String messageTitle = Localiser["organisation.caption.organisationEvent"]; + String messageTitle = Localiser["organisation.caption.event"]; AjaxResponse_Event responseData = new AjaxResponse_Event(model); // Validate session and referrer. @@ -309,7 +365,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers public IActionResult Ajax_StoreEvent(Model_Organisation_Events model) { String fn = GetType().Name + ".Ajax_StoreEvent"; - String messageTitle = Localiser["organisation.caption.organisationEvent"]; + String messageTitle = Localiser["organisation.caption.event"]; AjaxResponse_Event responseData = new AjaxResponse_Event(model); // Validate session and referrer. @@ -388,11 +444,33 @@ namespace Saxonite.Net.Core.Web.Online.Controllers organisationEvent.SportIdPrimary = model.ExtractSysId(model.EventSportIdPrimary); if (model.EventRegionIdCountry != null) organisationEvent.RegionIdCountry = model.ExtractSysId(model.EventRegionIdCountry); - if (model.EventDate != null) + if (model.EventAtDate != null) { - organisationEvent.EventAt = model.ParseDateFromForm(model.EventDate); - if (!StringUtil.IsEmpty(model.EventTime)) - organisationEvent.EventAt = DateUtil.SetTime(organisationEvent.EventAt, DateUtil.ParseExact(model.EventTime, "HH:mm")); + // 'At' date. + organisationEvent.EventAt = model.ParseDateFromForm(model.EventAtDate); + if (model.EventAtTimeSet && !StringUtil.IsBlank(model.EventAtTime)) + { + // For midnight (00:00) set +1 minute so that the value is treated as a valid start time. + if (model.EventAtTime.Equals("00:00")) + model.EventAtTime = "00:01"; + organisationEvent.EventAt = DateUtil.SetTime(organisationEvent.EventAt, DateUtil.ParseExact(model.EventAtTime, "HH:mm")); + } + if (model.EventToDateSet || model.EventToTimeSet) + { + // 'To' date. + organisationEvent.EventTo = organisationEvent.EventAt; + if (model.EventToDate != null && model.EventToDateSet) + organisationEvent.EventTo = model.ParseDateFromForm(model.EventToDate); + // 'To' time. + if (model.EventAtTimeSet && model.EventToTimeSet && !StringUtil.IsBlank(model.EventToTime)) + { + // For midnight (00:00) set +1 minute so that the value is treated as a valid finish time. + if (model.EventToTime.Equals("00:00")) + model.EventToTime = "00:01"; + organisationEvent.EventTo = DateUtil.SetTime(organisationEvent.EventTo ?? organisationEvent.EventAt, DateUtil.ParseExact(model.EventToTime, "HH:mm")); + } + } + else organisationEvent.EventTo = null; } if (model.EventTypeCode != null) organisationEvent.EventType = (Sax.EventType)EventTypeCodes.GetTypeForCode(model.EventTypeCode); diff --git a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController.cs b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController.cs index fd7b579..434a11b 100644 --- a/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController.cs +++ b/SaxoniteCoreWebOnline/Online/Controllers/OrganisationController.cs @@ -132,7 +132,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers OrganisationData organisationData = null; // Roles (any) required for organisation list. - List requiredRoles = new List() { Sax.OrganisationRole.Admin }; + List requiredRoles = new List() { Sax.OrganisationRole.Admin }; if (organisationRole > 0) requiredRoles.Add(organisationRole); @@ -141,9 +141,14 @@ namespace Saxonite.Net.Core.Web.Online.Controllers prmUserOrganisation.UserAccountIdsIncluded.Add(SessionUserAccountId); prmUserOrganisation.OrganisationStatusCat = SaxOrganisation.StatusCat.ActiveOnly; prmUserOrganisation.OrganisationMembersOnly = true; - prmUserOrganisation.OrganisationRolesAny.AddRange(requiredRoles); + prmUserOrganisation.OrganisationRolesAny.UnionWith(requiredRoles); prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly; + if (organisationRole == Sax.OrganisationRole.ScheduleAdmin) + { + prmUserOrganisation.OrganisationHasScheduledEvents = true; + } + // Restrict to specified Organisation. if (SysId.IsValid(filterOrganisationId)) { @@ -154,6 +159,10 @@ namespace Saxonite.Net.Core.Web.Online.Controllers prmUserOrganisation.OrganisationIdsIncluded.Clear(); } + // Clear 'Scheduled Events' flag if no organisations available. + if (prmUserOrganisation.OrganisationHasScheduledEvents && AccountMgr.GetUserOrganisationCount(prmUserOrganisation) < 1) + prmUserOrganisation.OrganisationHasScheduledEvents = false; + // Pick the first valid Organisation. ColumnDfn colOrganisationId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationId); ColumnDfn colOrganisationName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Name); diff --git a/SaxoniteCoreWebOnline/Online/Models/Model_Organisation_Events.cs b/SaxoniteCoreWebOnline/Online/Models/Model_Organisation_Events.cs index cecf2b2..9878843 100644 --- a/SaxoniteCoreWebOnline/Online/Models/Model_Organisation_Events.cs +++ b/SaxoniteCoreWebOnline/Online/Models/Model_Organisation_Events.cs @@ -1,4 +1,6 @@ -using Sarand.Net.Standard.Base.App; +using Microsoft.AspNetCore.Mvc.Rendering; +using NPOI.SS.Formula.Functions; +using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Bus; using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Utils; @@ -16,12 +18,23 @@ namespace Saxonite.Net.Core.Web.Online.Models //======================================================================= public class Model_Organisation_Events : SaxModel_Online { + //------------------------------------------------------------------- + // Definitions. + public enum PeriodType + { + FromThisWeek, + FromThisMonth, + FromLastMonth, + FromNextMonth, + Past, + } + //------------------------------------------------------------------- // Construction. public Model_Organisation_Events(SaxLocaliser localiser) : base(localiser) { - //AdditionalFiles_CSS.Add("css/sax-org-evt.css"); + AdditionalFiles_CSS.Add("css/sax-org-evt.css"); AdditionalFiles_JS.Add("js/sax-org-evt.js"); } @@ -31,6 +44,14 @@ namespace Saxonite.Net.Core.Web.Online.Models { public String OrganisationId { get; set; } public String OrganisationCaption { get; set; } + public class PeriodData + { + public String Type { get; set; } + public PeriodType PeriodType { get { return EnumUtil.ParseEnum(Type, PeriodType.FromThisWeek); } } + public String FromDate { get; set; } + public String ToDate { get; set; } + } + public PeriodData Period { get; } = new PeriodData(); public String Event { get; set; } } public EventFilterData Filter { get; } = new EventFilterData(); @@ -46,14 +67,36 @@ namespace Saxonite.Net.Core.Web.Online.Models // Region. public String EventRegionIdCountry { get; set; } // Event Content. - public String EventDate { get; set; } - public String EventTime { get; set; } + public String EventAtDate { get; set; } + public bool EventAtTimeSet { get; set; } + public String EventAtTime { get; set; } + public String EventDuration { get; set; } + public String EventDurationType { get; set; } + public String EventToDate { get; set; } + public bool EventToDateSet { get; set; } + public String EventToTime { get; set; } + public bool EventToTimeSet { get; set; } public String EventTypeCode { get; set; } public String EventSummary { get; set; } public String EventDetails { get; set; } public String EventStatusCode { get; set; } public SaStatus EventStatus { get { return SacsSystem.GetStatusForCode(EventStatusCode); } } + //------------------------------------------------------------------- + // Period types. + public IEnumerable EventPeriodTypesForDropdown + { + get + { + List values = new List(); + values.Add(new SelectListItem("From this week", PeriodType.FromThisWeek.ToString(), true)); + values.Add(new SelectListItem("From this month", PeriodType.FromThisMonth.ToString())); + values.Add(new SelectListItem("From last month", PeriodType.FromLastMonth.ToString())); + values.Add(new SelectListItem("From next month", PeriodType.FromNextMonth.ToString())); + return values; + } + } + //------------------------------------------------------------------- // Validation. //------------------------------------------------------------------- @@ -63,64 +106,125 @@ namespace Saxonite.Net.Core.Web.Online.Models // Event type. if (EventTypeCode != null) { + String controlName = nameof(EventTypeCode); if (StringUtil.IsEmpty(EventTypeCode)) - responseData.SetControlError(nameof(EventTypeCode), Localiser["msg.validation.mandatory.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); } - // Event date. - if (EventDate != null) + // Event At date. + if (EventAtDate != null) { - DateTime eventOn = ParseDateFromForm(EventDate); + String controlName = nameof(EventAtDate); + DateTime eventOn = ParseDateFromForm(EventAtDate); if (!DateUtil.IsValid(eventOn)) - responseData.SetControlError(nameof(EventDate), Localiser["msg.validation.mandatory.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); } - // Event time. - if (EventTime != null) + // Event At Time Set flag. + if (EventAtTimeSet) { + String controlName = nameof(EventAtTime); + if (StringUtil.IsBlank(EventAtTime)) + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); + } + + // Event At time. + if (EventAtTime != null && EventAtTimeSet) + { + String controlName = nameof(EventAtTime); + DateTime eventAt = DateUtil.ParseExact(EventAtTime, "HH:mm"); + if (StringUtil.IsBlank(EventAtTime)) + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); + else if (!DateUtil.IsValid(eventAt)) + responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]); + } + + // Event duration. + if (EventDuration != null) + { + String controlName = nameof(EventDuration); + } + + // Event duration type. + if (EventDurationType != null) + { + String controlName = nameof(EventDurationType); + } + + // Event To date. + if (EventToDate != null && EventToDateSet) + { + String controlName = nameof(EventToDate); + DateTime eventOn = ParseDateFromForm(EventToDate); + if (!DateUtil.IsValid(eventOn)) + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); + } + + // Event To Time Set flag. + if (EventToTimeSet) + { + String controlName = nameof(EventToTime); + if (StringUtil.IsBlank(EventToTime)) + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); + } + + // Event To time. + if (EventToTime != null && EventToTimeSet) + { + String controlName = nameof(EventToTime); + DateTime eventTo = DateUtil.ParseExact(EventToTime, "HH:mm"); + if (StringUtil.IsBlank(EventToTime)) + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); + else if (!DateUtil.IsValid(eventTo)) + responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]); } // Event summary. if (EventSummary != null) { - responseData.SetControlValue(nameof(EventSummary), EventSummary); + String controlName = nameof(EventSummary); + responseData.SetControlValue(controlName, EventSummary); if (StringUtil.IsEmpty(EventSummary)) - responseData.SetControlError(nameof(EventSummary), Localiser["msg.validation.mandatory.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); else if (StringUtil.GetLength(EventSummary) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Summary)) - responseData.SetControlError(nameof(EventSummary), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Summary)]); + responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Summary)]); } // Event details. if (EventDetails != null) { - responseData.SetControlValue(nameof(EventDetails), EventDetails); + String controlName = nameof(EventDetails); + responseData.SetControlValue(controlName, EventDetails); if (StringUtil.GetLength(EventDetails) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Details)) - responseData.SetControlError(nameof(EventDetails), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Details)]); + responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.OrganisationEvent_Details)]); } // Event sport. if (EventSportIdPrimary != null) { + String controlName = "EventSportPrimary"; SysId articleSportId = ExtractSysId(EventSportIdPrimary); if (!SysId.IsValid(articleSportId)) - responseData.SetControlError("EventSportPrimary", Localiser["msg.validation.mandatory.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); } // Event region. if (EventRegionIdCountry != null) { + String controlName = "EventRegionCountry"; SysId articleRegionId = ExtractSysId(EventRegionIdCountry); if (!SysId.IsValid(articleRegionId)) - responseData.SetControlError("EventRegionCountry", Localiser["msg.validation.mandatory.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); } // Event status. if (EventStatusCode != null) { + String controlName = nameof(EventStatus); if (StringUtil.IsEmpty(EventStatusCode)) - responseData.SetControlError(nameof(EventStatus), Localiser["msg.validation.mandatory.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); else if (!SaxOrganisationEvent.ValidStatuses.Contains(EventStatus)) - responseData.SetControlError(nameof(EventStatus), Localiser["msg.validation.invalid.value"]); + responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]); } return !responseData.HasControlErrors(); diff --git a/SaxoniteCoreWebOnline/SaxoniteCoreWebOnline.csproj b/SaxoniteCoreWebOnline/SaxoniteCoreWebOnline.csproj index 9b42383..48123d9 100644 --- a/SaxoniteCoreWebOnline/SaxoniteCoreWebOnline.csproj +++ b/SaxoniteCoreWebOnline/SaxoniteCoreWebOnline.csproj @@ -10,7 +10,8 @@ - + + @@ -34,6 +35,10 @@ true PreserveNewest + + true + PreserveNewest + true PreserveNewest diff --git a/SaxoniteCoreWebOnline/Views/Organisation/Events.cshtml b/SaxoniteCoreWebOnline/Views/Organisation/Events.cshtml index 57e3533..d19f50f 100644 --- a/SaxoniteCoreWebOnline/Views/Organisation/Events.cshtml +++ b/SaxoniteCoreWebOnline/Views/Organisation/Events.cshtml @@ -8,6 +8,7 @@ @* Filter Form *@ @@ -31,16 +32,18 @@
-
@Localiser["label.organisation"]
-
+
@Localiser["label.organisation"]
+
@Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId", @class = "FilterOrganisationId" })
-
@Localiser["label.search"]
-
+
@Localiser["label.period"]
+
@Html.DropDownListFor(model => model.Filter.Period.Type, Model.EventPeriodTypesForDropdown, new { @id = "cbFilterPeriodType", @class = "FilterPeriodType sax-select" })
+
@Localiser["label.search"]
+
@@ -59,40 +62,46 @@ @* Results Panel *@
-
+
+
+ + + + + + + + + + + +
@Localiser["label.date"]@Localiser["label.time"]@Localiser["label.summary"]@Localiser["label.published"]@Localiser["label.actions"]
+
+
@* Element templates *@
@* Item template *@ -
-
-
-
-
-
- @* Burger menu *@ - -
-
-
-
-
-
-
-
-
-
@Localiser["label.created"]: 
-
@Localiser["label.published"]: 
-
-
-
-
+ + + + + + + + +
+
+ @* Burger menu *@ + +
+
@* Burger dropdown item template - ul is ignored *@
    diff --git a/SaxoniteCoreWebOnline/Views/Organisation/Panel-EventDialog.cshtml b/SaxoniteCoreWebOnline/Views/Organisation/Panel-EventDialog.cshtml index 9a0cc12..c000c4e 100644 --- a/SaxoniteCoreWebOnline/Views/Organisation/Panel-EventDialog.cshtml +++ b/SaxoniteCoreWebOnline/Views/Organisation/Panel-EventDialog.cshtml @@ -2,6 +2,11 @@ @inject SaxLocaliser Localiser @{ /* Organisation Events - Event dialog panel */ + //Model.AdditionalFiles_CSS.Add("lib/jquery-timepicker/jquery.timepicker.min.css"); + //Model.AdditionalFiles_JS.Add("lib/jquery-timepicker/jquery.timepicker.min.js"); + //Model.AdditionalFiles_CSS.Add("lib/bootstrap4-datetimepicker/bootstrap-datetimepicker.min.css"); + //Model.AdditionalFiles_JS.Add("lib/moment.js/moment.min.js"); + //Model.AdditionalFiles_JS.Add("lib/bootstrap4-datetimepicker/bootstrap-datetimepicker.min.js"); }