From 1feda1b520125bb33d3eb1c95ff668e5bc6d51fb Mon Sep 17 00:00:00 2001 From: James Kolpack Date: Mon, 20 Jan 2014 22:40:40 -0500 Subject: [PATCH] Basic implementation - largely untested --- Web/Controllers/CreateLogController.cs | 35 +++++ Web/ViewModels/CreateLog/EditPastViewModel.cs | 132 ++++++++++++++++++ Web/Views/CreateLog/EditPast.cshtml | 21 +++ Web/Views/CreateLog/RecentLogs.cshtml | 4 + Web/Web.csproj | 2 + 5 files changed, 194 insertions(+) create mode 100644 Web/ViewModels/CreateLog/EditPastViewModel.cs create mode 100644 Web/Views/CreateLog/EditPast.cshtml diff --git a/Web/Controllers/CreateLogController.cs b/Web/Controllers/CreateLogController.cs index 438b7fd..da27b8d 100644 --- a/Web/Controllers/CreateLogController.cs +++ b/Web/Controllers/CreateLogController.cs @@ -5,6 +5,7 @@ using MileageTraker.Web.Attributes; using MileageTraker.Web.Models; using MileageTraker.Web.ViewModels; using MileageTraker.Web.ViewModels.CreateLog; +using MileageTraker.Web.ViewModels.Log; namespace MileageTraker.Web.Controllers { @@ -35,6 +36,40 @@ namespace MileageTraker.Web.Controllers return View(model); } + public ActionResult EditPast(int id) + { + var log = DataService.GetLog(id); + var viewModel = new EditPastViewModel(log) + { + Purpose = { Available = GetPurposeTypesSelectList() } + }; + return View(viewModel); + } + + [HttpPost] + [ActionLog] + public ActionResult EditPast(EditPastViewModel viewModel) + { + if (ModelState.IsValid) + { + var log = DataService.GetLog(viewModel.LogId); + viewModel.SetProperties(log); + + if (viewModel.Purpose != null) + log.Purpose = + DataService.GetPurposeTypes() + .First(pt => pt.PurposeTypeId == viewModel.Purpose.Selected); + + DataService.UpdateLog(log); + + TempData["StatusMessage"] = "Log updated"; + return RedirectToAction("Index"); + } + + viewModel.Purpose.Available = GetPurposeTypesSelectList(); + return View(viewModel); + } + [HttpParamAction] [HttpPost] public ViewResult Edit(CreateLogViewModel model) diff --git a/Web/ViewModels/CreateLog/EditPastViewModel.cs b/Web/ViewModels/CreateLog/EditPastViewModel.cs new file mode 100644 index 0000000..8c93248 --- /dev/null +++ b/Web/ViewModels/CreateLog/EditPastViewModel.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Web.Mvc; +using AutoMapper; +using MileageTraker.Web.Attributes; +using MileageTraker.Web.DAL; +using MileageTraker.Web.Models; +using MileageTraker.Web.Utility; + +namespace MileageTraker.Web.ViewModels.CreateLog +{ + public class EditPastViewModel : IValidatableObject + { + [HiddenInput(DisplayValue = false)] + public int LogId { get; set; } + + [Required(ErrorMessage = "Required")] + [Remote("Exists", "Vehicle", ErrorMessage = "ID not found")] + [StringLength(6, MinimumLength = 4, ErrorMessage = "Must be a 4 digit number")] + [Display(Name = "Vehicle ID")] + [InputSize("mini")] + [RegularExpression(@"\d+", ErrorMessage = "Must be all numbers")] + public string VehicleId { get; set; } + + [Required(ErrorMessage = "Required")] + [Range(1, 500000, ErrorMessage = "Between 1 and 500k")] + [Display(Name = "End Odometer")] + [Units("Miles")] + [InputSize("small")] + [RegularExpression(@"\d+", ErrorMessage = "Must be all numbers")] + public string EndOdometer { get; set; } + + [Required(ErrorMessage = "Required")] + [Display(Name = "Type")] + [NoEditLabel] + public MileageLogTypeWrapper LogType { get; set; } + [Required(ErrorMessage = "Required")] + [Display(Name = "Destination City")] + [InputSize("medium")] + [StringLength(64, MinimumLength = 3, ErrorMessage = "Minimum 3 characters")] + public string CityName { get; set; } + + [Display(Name = "Purpose")] + [Required] + public SelectListViewModel Purpose { get; set; } + + [InputSize("large")] + [StringLength(64, MinimumLength = 3, ErrorMessage = "Minimum 3 characters")] + public string Notes { get; set; } + + [RegularExpression(@"\d+\.\d{3}", ErrorMessage = "Enter all 3 decimal places")] + [Display(Name = "Gas Purchased")] + [DisplayFormat(DataFormatString = "{0:0.000}", ApplyFormatInEditMode = true)] + [Units("Gallons")] + [FormatHint("n.nnn")] + [InputSize("mini")] + public string GasPurchased { get; set; } + + [Required(ErrorMessage = "Required")] + [DataType(DataType.Date)] + [DisplayFormat(DataFormatString = @"{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)] + [DenyFutureDate(ErrorMessage = "Future date")] + [DenyPreviousMonthDate(ErrorMessage = "Previous Month")] + [FormatHint("mm/dd/yyyy")] + [InputSize("small")] + public DateTime Date { get; set; } + + static EditPastViewModel() + { + Mapper.CreateMap().ConvertUsing(Convert.ToInt32); + Mapper.CreateMap().ConvertUsing(Convert.ToDouble); + Mapper.CreateMap().ConvertUsing(new DateTimeTypeConverter()); + Mapper.CreateMap() + .ForMember(u => u.Purpose, opt => opt.Ignore()); + Mapper.CreateMap() + .ForMember(vm => vm.Date, opt => opt.MapFrom(m => m.Date.ToString("d"))) + .ForMember(u => u.Purpose, opt => opt.Ignore()); + } + + public EditPastViewModel() + { + // view will crash if this isn't instantiated + LogType = new MileageLogTypeWrapper(); + Purpose = new SelectListViewModel(); + } + + public EditPastViewModel(Models.Log log) : this() + { + Mapper.Map(log, this); + if (log.Purpose != null) + Purpose.Selected = log.Purpose.PurposeTypeId; + } + + public Models.Log GetLog() + { + var log = new Models.Log(); + Mapper.Map(this, log); + return log; + } + + public void SetProperties(Models.Log log) + { + Mapper.DynamicMap(this, log); + } + + public IEnumerable Validate(ValidationContext validationContext) + { + if (LogType == MileageLogType.GasPurchase + && (string.IsNullOrEmpty(GasPurchased) || Math.Abs(double.Parse(GasPurchased) - 0) < double.Epsilon)) + yield return new ValidationResult("Enter amount of gas purchased", new [] {"GasPurchased"}); + + if (LogType.Value == 0) + yield return new ValidationResult("Required", new[] { "LogType" }); + + ValidationResult result = null; + try + { + using (var dataService = new DataService()) + { + dataService.ValidateOdometerChronology(VehicleId, int.Parse(EndOdometer), Date); + } + } + catch (Exception ex) + { + result = new ValidationResult(ex.Message, new [] {"EndOdometer"}); + } + if (result != null) + yield return result; + } + } +} \ No newline at end of file diff --git a/Web/Views/CreateLog/EditPast.cshtml b/Web/Views/CreateLog/EditPast.cshtml new file mode 100644 index 0000000..4fc48ed --- /dev/null +++ b/Web/Views/CreateLog/EditPast.cshtml @@ -0,0 +1,21 @@ +@model MileageTraker.Web.ViewModels.CreateLog.EditPastViewModel +@{ + + ViewBag.Title = "Edit Mileage Log"; +} + +@Html.Partial("_StatusMessage") + +

@ViewBag.Title

+ +@using (Html.BeginForm("EditPast", "CreateLog", FormMethod.Post, new { @class = "form-horizontal well center-content" })) +{ +
+ + @Html.Partial("_ValidationSummary") + @Html.EditorForModel() +
+ +
+
+} diff --git a/Web/Views/CreateLog/RecentLogs.cshtml b/Web/Views/CreateLog/RecentLogs.cshtml index 04c03da..b64ab7d 100644 --- a/Web/Views/CreateLog/RecentLogs.cshtml +++ b/Web/Views/CreateLog/RecentLogs.cshtml @@ -20,6 +20,7 @@ Type + @foreach (var log in Model) @@ -37,6 +38,9 @@ @Html.Encode(log.LogType.Enum.GetDisplayName()) + + @Html.ActionLink("Edit", "EditPast", new { id = log.LogId }, new { @class = "btn btn-mini" }) + } diff --git a/Web/Web.csproj b/Web/Web.csproj index 716ebf4..1c4fc02 100644 --- a/Web/Web.csproj +++ b/Web/Web.csproj @@ -179,6 +179,7 @@ + @@ -328,6 +329,7 @@ +