Merge pull request #435 from hargata/Hargata/reminder.tag

Reminder Tags
This commit is contained in:
Hargata Softworks 2024-03-26 08:47:14 -06:00 committed by GitHub
commit 470dd4d78a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 94 additions and 13 deletions

View File

@ -1683,7 +1683,8 @@ namespace CarCareTracker.Controllers
ReminderMileageInterval = result.ReminderMileageInterval, ReminderMileageInterval = result.ReminderMileageInterval,
ReminderMonthInterval = result.ReminderMonthInterval, ReminderMonthInterval = result.ReminderMonthInterval,
CustomMileageInterval = result.CustomMileageInterval, CustomMileageInterval = result.CustomMileageInterval,
CustomMonthInterval = result.CustomMonthInterval CustomMonthInterval = result.CustomMonthInterval,
Tags = result.Tags
}; };
return PartialView("_ReminderRecordModal", convertedResult); return PartialView("_ReminderRecordModal", convertedResult);
} }

View File

@ -73,7 +73,8 @@ namespace CarCareTracker.Helper
Description = reminder.Description, Description = reminder.Description,
Notes = reminder.Notes, Notes = reminder.Notes,
Metric = reminder.Metric, Metric = reminder.Metric,
IsRecurring = reminder.IsRecurring IsRecurring = reminder.IsRecurring,
Tags = reminder.Tags
}; };
if (reminder.Metric == ReminderMetric.Both) if (reminder.Metric == ReminderMetric.Both)
{ {

View File

@ -14,5 +14,6 @@
public ReminderMileageInterval ReminderMileageInterval { get; set; } = ReminderMileageInterval.FiveThousandMiles; public ReminderMileageInterval ReminderMileageInterval { get; set; } = ReminderMileageInterval.FiveThousandMiles;
public ReminderMonthInterval ReminderMonthInterval { get; set; } = ReminderMonthInterval.OneYear; public ReminderMonthInterval ReminderMonthInterval { get; set; } = ReminderMonthInterval.OneYear;
public ReminderMetric Metric { get; set; } = ReminderMetric.Date; public ReminderMetric Metric { get; set; } = ReminderMetric.Date;
public List<string> Tags { get; set; } = new List<string>();
} }
} }

View File

@ -14,6 +14,7 @@
public ReminderMileageInterval ReminderMileageInterval { get; set; } = ReminderMileageInterval.FiveThousandMiles; public ReminderMileageInterval ReminderMileageInterval { get; set; } = ReminderMileageInterval.FiveThousandMiles;
public ReminderMonthInterval ReminderMonthInterval { get; set; } = ReminderMonthInterval.OneYear; public ReminderMonthInterval ReminderMonthInterval { get; set; } = ReminderMonthInterval.OneYear;
public ReminderMetric Metric { get; set; } = ReminderMetric.Date; public ReminderMetric Metric { get; set; } = ReminderMetric.Date;
public List<string> Tags { get; set; } = new List<string>();
public ReminderRecord ToReminderRecord() public ReminderRecord ToReminderRecord()
{ {
return new ReminderRecord return new ReminderRecord
@ -29,7 +30,8 @@
ReminderMonthInterval = ReminderMonthInterval, ReminderMonthInterval = ReminderMonthInterval,
CustomMileageInterval = CustomMileageInterval, CustomMileageInterval = CustomMileageInterval,
CustomMonthInterval = CustomMonthInterval, CustomMonthInterval = CustomMonthInterval,
Notes = Notes Notes = Notes,
Tags = Tags
}; };
} }
} }

View File

@ -17,5 +17,6 @@
/// Recurring Reminders /// Recurring Reminders
/// </summary> /// </summary>
public bool IsRecurring { get; set; } = false; public bool IsRecurring { get; set; } = false;
public List<string> Tags { get; set; } = new List<string>();
} }
} }

View File

@ -42,6 +42,14 @@
<input class="form-check-input" type="radio" name="reminderMetricOptions" id="reminderMetricBoth" value="@(ReminderMetric.Both)" checked="@(Model.Metric == ReminderMetric.Both)"> <input class="form-check-input" type="radio" name="reminderMetricOptions" id="reminderMetricBoth" value="@(ReminderMetric.Both)" checked="@(Model.Metric == ReminderMetric.Both)">
<label class="form-check-label" for="reminderMetricBoth">@translator.Translate(userLanguage,"Whichever comes first")</label> <label class="form-check-label" for="reminderMetricBoth">@translator.Translate(userLanguage,"Whichever comes first")</label>
</div> </div>
<div class="d-grid"></div>
<label for="reminderRecordTag">@translator.Translate(userLanguage, "Tags(optional)")</label>
<select multiple class="form-select" id="reminderRecordTag">
@foreach (string tag in Model.Tags)
{
<!option value="@tag">@tag</!option>
}
</select>
</div> </div>
<div class="col-md-6 col-12"> <div class="col-md-6 col-12">
<label for="reminderNotes">@translator.Translate(userLanguage,"Notes(optional)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label> <label for="reminderNotes">@translator.Translate(userLanguage,"Notes(optional)")<a class="link-underline link-underline-opacity-0" onclick="showLinks(this)"><i class="bi bi-markdown ms-2"></i></a></label>

View File

@ -6,15 +6,26 @@
var userConfig = config.GetUserConfig(User); var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage; var userLanguage = userConfig.UserLanguage;
var hasRefresh = Model.Where(x => (x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue) && x.IsRecurring).Any(); var hasRefresh = Model.Where(x => (x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue) && x.IsRecurring).Any();
var recordTags = Model.SelectMany(x => x.Tags).Distinct();
} }
<div class="row"> <div class="row">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<div class="d-flex align-items-center flex-wrap"> <div class="d-flex align-items-center flex-wrap">
<span class="ms-2 badge bg-success">@($"{translator.Translate(userLanguage, "# of Reminders")}: {Model.Count()}")</span> <span class="ms-2 badge bg-success" data-aggregate-type="count">@($"{translator.Translate(userLanguage, "# of Reminders")}: {Model.Count()}")</span>
<span class="ms-2 badge bg-secondary">@($"{translator.Translate(userLanguage, "Past Due")}: {Model.Where(x => x.Urgency == ReminderUrgency.PastDue).Count()}")</span> <span class="ms-2 badge bg-secondary" data-aggregate-type="pastdue-count">@($"{translator.Translate(userLanguage, "Past Due")}: {Model.Where(x => x.Urgency == ReminderUrgency.PastDue).Count()}")</span>
<span class="ms-2 badge bg-danger">@($"{translator.Translate(userLanguage, "Very Urgent")}: {Model.Where(x=>x.Urgency == ReminderUrgency.VeryUrgent).Count()}")</span> <span class="ms-2 badge bg-danger" data-aggregate-type="veryurgent-count">@($"{translator.Translate(userLanguage, "Very Urgent")}: {Model.Where(x => x.Urgency == ReminderUrgency.VeryUrgent).Count()}")</span>
<span class="ms-2 badge bg-warning">@($"{translator.Translate(userLanguage, "Urgent")}: {Model.Where(x => x.Urgency == ReminderUrgency.Urgent).Count()}")</span> <span class="ms-2 badge text-bg-warning" data-aggregate-type="urgent-count">@($"{translator.Translate(userLanguage, "Urgent")}: {Model.Where(x => x.Urgency == ReminderUrgency.Urgent).Count()}")</span>
<span class="ms-2 badge bg-success">@($"{translator.Translate(userLanguage, "Not Urgent")}: {Model.Where(x => x.Urgency == ReminderUrgency.NotUrgent).Count()}")</span> <span class="ms-2 badge bg-success" data-aggregate-type="noturgent-count">@($"{translator.Translate(userLanguage, "Not Urgent")}: {Model.Where(x => x.Urgency == ReminderUrgency.NotUrgent).Count()}")</span>
@foreach (string recordTag in recordTags)
{
<span onclick="filterReminderTable(this)" class="user-select-none ms-2 rounded-pill badge bg-secondary tagfilter" style="cursor:pointer;">@recordTag</span>
}
<datalist id="tagList">
@foreach (string recordTag in recordTags)
{
<!option value="@recordTag"></!option>
}
</datalist>
</div> </div>
<div> <div>
<button onclick="showAddReminderModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Add Reminder")</button> <button onclick="showAddReminderModal()" class="btn btn-primary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Add Reminder")</button>
@ -45,7 +56,7 @@
<tbody> <tbody>
@foreach (ReminderRecordViewModel reminderRecord in Model) @foreach (ReminderRecordViewModel reminderRecord in Model)
{ {
<tr class="d-flex user-select-none" style="cursor:pointer;" onmouseup="stopEvent()" ontouchstart="detectRowLongTouch(this)" ontouchend="detectRowTouchEndPremature(this)" data-rowId="@reminderRecord.Id" oncontextmenu="showTableContextMenu(this)" onmousemove="rangeMouseMove(this)" onclick="handleTableRowClick(this, showEditReminderRecordModal,@reminderRecord.Id)"> <tr class="d-flex user-select-none" style="cursor:pointer;" onmouseup="stopEvent()" ontouchstart="detectRowLongTouch(this)" ontouchend="detectRowTouchEndPremature(this)" data-rowId="@reminderRecord.Id" oncontextmenu="showTableContextMenu(this)" onmousemove="rangeMouseMove(this)" onclick="handleTableRowClick(this, showEditReminderRecordModal,@reminderRecord.Id)" data-tags='@string.Join(" ", reminderRecord.Tags)'>
@if (reminderRecord.Urgency == ReminderUrgency.VeryUrgent) @if (reminderRecord.Urgency == ReminderUrgency.VeryUrgent)
{ {
<td class="col-1"><span class="badge text-bg-danger">@translator.Translate(userLanguage, "Very Urgent")</span></td> <td class="col-1"><span class="badge text-bg-danger">@translator.Translate(userLanguage, "Very Urgent")</span></td>
@ -74,7 +85,7 @@
{ {
<td class="col-2">@reminderRecord.Metric</td> <td class="col-2">@reminderRecord.Metric</td>
} }
<td class="@(hasRefresh ? "col-4" : "col-5")">@reminderRecord.Description</td> <td class="@(hasRefresh ? "col-4" : "col-5")" data-record-type='cost'>@reminderRecord.Description</td>
<td class="col-3 text-truncate">@CarCareTracker.Helper.StaticHelper.TruncateStrings(reminderRecord.Notes)</td> <td class="col-3 text-truncate">@CarCareTracker.Helper.StaticHelper.TruncateStrings(reminderRecord.Notes)</td>
@if (hasRefresh) @if (hasRefresh)
{ {

View File

@ -91,7 +91,7 @@ function generateReminderItem(id, urgency, description) {
case "PastDue": case "PastDue":
return `<p class="badge text-wrap bg-secondary reminder-calendar-item mb-2" onclick='showCalendarReminderModal(${id})'>${encodeHTMLInput(description)}</p>`; return `<p class="badge text-wrap bg-secondary reminder-calendar-item mb-2" onclick='showCalendarReminderModal(${id})'>${encodeHTMLInput(description)}</p>`;
case "Urgent": case "Urgent":
return `<p class="badge text-wrap bg-warning reminder-calendar-item mb-2" onclick='showCalendarReminderModal(${id})'>${encodeHTMLInput(description)}</p>`; return `<p class="badge text-wrap text-bg-warning reminder-calendar-item mb-2" onclick='showCalendarReminderModal(${id})'>${encodeHTMLInput(description)}</p>`;
case "NotUrgent": case "NotUrgent":
return `<p class="badge text-wrap bg-success reminder-calendar-item mb-2" onclick='showCalendarReminderModal(${id})'>${encodeHTMLInput(description)}</p>`; return `<p class="badge text-wrap bg-success reminder-calendar-item mb-2" onclick='showCalendarReminderModal(${id})'>${encodeHTMLInput(description)}</p>`;
} }

View File

@ -3,6 +3,7 @@
if (data) { if (data) {
$("#reminderRecordModalContent").html(data); $("#reminderRecordModalContent").html(data);
initDatePicker($('#reminderDate'), true); initDatePicker($('#reminderDate'), true);
initTagSelector($("#reminderRecordTag"));
$("#reminderRecordModal").modal("show"); $("#reminderRecordModal").modal("show");
$('#reminderRecordModal').off('shown.bs.modal').on('shown.bs.modal', function () { $('#reminderRecordModal').off('shown.bs.modal').on('shown.bs.modal', function () {
if (getGlobalConfig().useMarkDown) { if (getGlobalConfig().useMarkDown) {
@ -166,6 +167,7 @@ function getAndValidateReminderRecordValues() {
var reminderIsRecurring = $("#reminderIsRecurring").is(":checked"); var reminderIsRecurring = $("#reminderIsRecurring").is(":checked");
var reminderRecurringMonth = $("#reminderRecurringMonth").val(); var reminderRecurringMonth = $("#reminderRecurringMonth").val();
var reminderRecurringMileage = $("#reminderRecurringMileage").val(); var reminderRecurringMileage = $("#reminderRecurringMileage").val();
var reminderTags = $("#reminderRecordTag").val();
var reminderCustomMileageInterval = customMileageInterval; var reminderCustomMileageInterval = customMileageInterval;
var vehicleId = GetVehicleId().vehicleId; var vehicleId = GetVehicleId().vehicleId;
var reminderId = getReminderRecordModelData().id; var reminderId = getReminderRecordModelData().id;
@ -215,7 +217,8 @@ function getAndValidateReminderRecordValues() {
reminderMileageInterval: reminderRecurringMileage, reminderMileageInterval: reminderRecurringMileage,
reminderMonthInterval: reminderRecurringMonth, reminderMonthInterval: reminderRecurringMonth,
customMileageInterval: customMileageInterval, customMileageInterval: customMileageInterval,
customMonthInterval: customMonthInterval customMonthInterval: customMonthInterval,
tags: reminderTags
} }
} }
function createPlanRecordFromReminder(reminderRecordId) { function createPlanRecordFromReminder(reminderRecordId) {
@ -239,4 +242,55 @@ function createPlanRecordFromReminder(reminderRecordId) {
$("#planRecordModalContent").html(data); $("#planRecordModalContent").html(data);
$("#planRecordModal").modal("show"); $("#planRecordModal").modal("show");
}); });
}
function filterReminderTable(sender) {
var rowData = $(`#reminder-tab-pane table tbody tr`);
if (sender == undefined) {
rowData.removeClass('override-hide');
return;
}
var tagName = sender.textContent;
//check for other applied filters
if ($(sender).hasClass("bg-primary")) {
rowData.removeClass('override-hide');
$(sender).removeClass('bg-primary');
$(sender).addClass('bg-secondary');
updateReminderAggregateLabels();
} else {
//hide table rows.
rowData.addClass('override-hide');
$(`[data-tags~='${tagName}']`).removeClass('override-hide');
updateReminderAggregateLabels();
if ($(".tagfilter.bg-primary").length > 0) {
//disabling other filters
$(".tagfilter.bg-primary").addClass('bg-secondary');
$(".tagfilter.bg-primary").removeClass('bg-primary');
}
$(sender).addClass('bg-primary');
$(sender).removeClass('bg-secondary');
}
}
function updateReminderAggregateLabels() {
//update main count
var newCount = $("[data-record-type='cost']").parent(":not('.override-hide')").length;
var countLabel = $("[data-aggregate-type='count']");
countLabel.text(`${countLabel.text().split(':')[0]}: ${newCount}`);
//update labels
//paste due
var pastDueCount = $("tr td span.badge.text-bg-secondary").parents("tr:not('.override-hide')").length;
var pastDueLabel = $('[data-aggregate-type="pastdue-count"]');
pastDueLabel.text(`${pastDueLabel.text().split(':')[0]}: ${pastDueCount}`);
//very urgent
var veryUrgentCount = $("tr td span.badge.text-bg-danger").parents("tr:not('.override-hide')").length;
var veryUrgentLabel = $('[data-aggregate-type="veryurgent-count"]');
veryUrgentLabel.text(`${veryUrgentLabel.text().split(':')[0]}: ${veryUrgentCount}`);
//urgent
var urgentCount = $("tr td span.badge.text-bg-warning").parents("tr:not('.override-hide')").length;
var urgentLabel = $('[data-aggregate-type="urgent-count"]');
urgentLabel.text(`${urgentLabel.text().split(':')[0]}: ${urgentCount}`);
//not urgent
var notUrgentCount = $("tr td span.badge.text-bg-success").parents("tr:not('.override-hide')").length;
var notUrgentLabel = $('[data-aggregate-type="noturgent-count"]');
notUrgentLabel.text(`${notUrgentLabel.text().split(':')[0]}: ${notUrgentCount}`);
} }

View File

@ -336,7 +336,7 @@ function updateAggregateLabels() {
//Count //Count
var newCount = $("[data-record-type='cost']").parent(":not('.override-hide')").length; var newCount = $("[data-record-type='cost']").parent(":not('.override-hide')").length;
var countLabel = $("[data-aggregate-type='count']"); var countLabel = $("[data-aggregate-type='count']");
countLabel.text(`${countLabel.text().split(':')[0]}: ${newCount}`) countLabel.text(`${countLabel.text().split(':')[0]}: ${newCount}`);
} }
function uploadVehicleFilesAsync(event) { function uploadVehicleFilesAsync(event) {

View File

@ -246,12 +246,14 @@ function showAddReminderModal(reminderModalInput) {
$.post('/Vehicle/GetAddReminderRecordPartialView', { reminderModel: reminderModalInput }, function (data) { $.post('/Vehicle/GetAddReminderRecordPartialView', { reminderModel: reminderModalInput }, function (data) {
$("#reminderRecordModalContent").html(data); $("#reminderRecordModalContent").html(data);
initDatePicker($('#reminderDate'), true); initDatePicker($('#reminderDate'), true);
initTagSelector($("#reminderRecordTag"));
$("#reminderRecordModal").modal("show"); $("#reminderRecordModal").modal("show");
}); });
} else { } else {
$.post('/Vehicle/GetAddReminderRecordPartialView', function (data) { $.post('/Vehicle/GetAddReminderRecordPartialView', function (data) {
$("#reminderRecordModalContent").html(data); $("#reminderRecordModalContent").html(data);
initDatePicker($('#reminderDate'), true); initDatePicker($('#reminderDate'), true);
initTagSelector($("#reminderRecordTag"));
$("#reminderRecordModal").modal("show"); $("#reminderRecordModal").modal("show");
}); });
} }