feat: implement preview work units preference with local storage support
All checks were successful
Publish Container / publish (push) Successful in 3m16s
All checks were successful
Publish Container / publish (push) Successful in 3m16s
This commit is contained in:
parent
158906fa28
commit
0991128b30
4 changed files with 104 additions and 5 deletions
|
|
@ -199,6 +199,8 @@ else
|
||||||
@code {
|
@code {
|
||||||
[Parameter] public string? YearMonth { get; set; }
|
[Parameter] public string? YearMonth { get; set; }
|
||||||
|
|
||||||
|
private const string IncludePreviewPreferenceKey = "worktracker.includePreviewWorkUnits";
|
||||||
|
|
||||||
private DateOnly firstOfMonth;
|
private DateOnly firstOfMonth;
|
||||||
private bool loading = true;
|
private bool loading = true;
|
||||||
private List<CalendarCell?[]> weeks = [];
|
private List<CalendarCell?[]> weeks = [];
|
||||||
|
|
@ -222,6 +224,22 @@ else
|
||||||
await LoadMonth();
|
await LoadMonth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (!firstRender)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var savedIncludePreview = await JS.InvokeAsync<bool?>("workTrackerPreferences.getBool", IncludePreviewPreferenceKey);
|
||||||
|
if (savedIncludePreview.HasValue && savedIncludePreview.Value != includePreviewTotals)
|
||||||
|
{
|
||||||
|
includePreviewTotals = savedIncludePreview.Value;
|
||||||
|
await LoadMonth();
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task LoadMonth()
|
private async Task LoadMonth()
|
||||||
{
|
{
|
||||||
loading = true;
|
loading = true;
|
||||||
|
|
@ -269,6 +287,7 @@ else
|
||||||
private async Task OnIncludePreviewTotalsChanged(ChangeEventArgs e)
|
private async Task OnIncludePreviewTotalsChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
includePreviewTotals = e.Value is bool value && value;
|
includePreviewTotals = e.Value is bool value && value;
|
||||||
|
await JS.InvokeVoidAsync("workTrackerPreferences.setBool", IncludePreviewPreferenceKey, includePreviewTotals);
|
||||||
await LoadMonth();
|
await LoadMonth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
@using System.Globalization
|
@using System.Globalization
|
||||||
@inject global::WorkTracker.Services.WorkDays.IWorkDayService WorkDayService
|
@inject global::WorkTracker.Services.WorkDays.IWorkDayService WorkDayService
|
||||||
|
@inject IJSRuntime JS
|
||||||
|
|
||||||
<PageTitle>Monthly Summary</PageTitle>
|
<PageTitle>Monthly Summary</PageTitle>
|
||||||
|
|
||||||
|
|
@ -209,6 +210,7 @@ else if (viewMode == SummaryViewMode.Timesheet && timesheet is not null)
|
||||||
[Parameter] public string? YearMonth { get; set; }
|
[Parameter] public string? YearMonth { get; set; }
|
||||||
|
|
||||||
private static readonly CultureInfo ItalianCulture = CultureInfo.GetCultureInfo("it-IT");
|
private static readonly CultureInfo ItalianCulture = CultureInfo.GetCultureInfo("it-IT");
|
||||||
|
private const string IncludePreviewPreferenceKey = "worktracker.includePreviewWorkUnits";
|
||||||
|
|
||||||
private DateOnly currentMonth;
|
private DateOnly currentMonth;
|
||||||
private bool loading = true;
|
private bool loading = true;
|
||||||
|
|
@ -231,9 +233,26 @@ else if (viewMode == SummaryViewMode.Timesheet && timesheet is not null)
|
||||||
await LoadSummary();
|
await LoadSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (!firstRender)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var savedIncludePreview = await JS.InvokeAsync<bool?>("workTrackerPreferences.getBool", IncludePreviewPreferenceKey);
|
||||||
|
if (savedIncludePreview.HasValue && savedIncludePreview.Value != includePreview)
|
||||||
|
{
|
||||||
|
includePreview = savedIncludePreview.Value;
|
||||||
|
await LoadSummary();
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task OnIncludePreviewChanged(ChangeEventArgs e)
|
private async Task OnIncludePreviewChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
includePreview = e.Value is bool value && value;
|
includePreview = e.Value is bool value && value;
|
||||||
|
await JS.InvokeVoidAsync("workTrackerPreferences.setBool", IncludePreviewPreferenceKey, includePreview);
|
||||||
await LoadSummary();
|
await LoadSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -715,22 +715,28 @@ h1:focus {
|
||||||
|
|
||||||
.timesheet-summary-table thead th {
|
.timesheet-summary-table thead th {
|
||||||
background-color: var(--wt-summary-head-bg);
|
background-color: var(--wt-summary-head-bg);
|
||||||
white-space: nowrap;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timesheet-summary-table th,
|
.timesheet-summary-table th,
|
||||||
.timesheet-summary-table td {
|
.timesheet-summary-table td {
|
||||||
min-width: 2.2rem;
|
min-width: 2.2rem;
|
||||||
padding: 0.25rem 0.12rem;
|
padding: 0.35rem 0.16rem;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timesheet-summary-sticky-column {
|
.timesheet-summary-sticky-column {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
min-width: 15rem !important;
|
min-width: 6.25rem !important;
|
||||||
|
max-width: 6.25rem;
|
||||||
background-color: var(--wt-summary-sticky-bg);
|
background-color: var(--wt-summary-sticky-bg);
|
||||||
|
white-space: normal;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
word-break: break-word;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timesheet-summary-table thead .timesheet-summary-sticky-column {
|
.timesheet-summary-table thead .timesheet-summary-sticky-column {
|
||||||
|
|
@ -739,8 +745,11 @@ h1:focus {
|
||||||
}
|
}
|
||||||
|
|
||||||
.timesheet-summary-total-column {
|
.timesheet-summary-total-column {
|
||||||
|
position: sticky;
|
||||||
|
right: 0;
|
||||||
|
z-index: 2;
|
||||||
background-color: var(--wt-summary-head-bg);
|
background-color: var(--wt-summary-head-bg);
|
||||||
min-width: 3.3rem !important;
|
min-width: 3.5rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timesheet-summary-table tbody tr:nth-child(odd) td,
|
.timesheet-summary-table tbody tr:nth-child(odd) td,
|
||||||
|
|
@ -748,6 +757,18 @@ h1:focus {
|
||||||
background-color: var(--wt-summary-row-alt);
|
background-color: var(--wt-summary-row-alt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timesheet-summary-table tbody tr:nth-child(odd) .timesheet-summary-total-column {
|
||||||
|
background-color: var(--wt-summary-row-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
.timesheet-summary-table tbody .timesheet-summary-total-column {
|
||||||
|
background-color: var(--wt-summary-sticky-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.timesheet-summary-table thead .timesheet-summary-total-column {
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
.timesheet-summary-table .timesheet-summary-day-danger {
|
.timesheet-summary-table .timesheet-summary-day-danger {
|
||||||
background-color: #f8d7da !important;
|
background-color: #f8d7da !important;
|
||||||
}
|
}
|
||||||
|
|
@ -821,7 +842,16 @@ h1:focus {
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
@media (max-width: 767.98px) {
|
||||||
.timesheet-summary-sticky-column {
|
.timesheet-summary-sticky-column {
|
||||||
min-width: 12rem !important;
|
min-width: 4.75rem !important;
|
||||||
|
max-width: 4.75rem;
|
||||||
|
padding-left: 0.3rem !important;
|
||||||
|
padding-right: 0.3rem !important;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timesheet-summary-total-column {
|
||||||
|
min-width: 3.1rem !important;
|
||||||
|
font-size: 0.82rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timesheet-summary-day-popup {
|
.timesheet-summary-day-popup {
|
||||||
|
|
|
||||||
|
|
@ -55,4 +55,35 @@ window.workTrackerTheme = (() => {
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
window.workTrackerPreferences = {
|
||||||
|
getBool(key) {
|
||||||
|
try {
|
||||||
|
const value = localStorage.getItem(key);
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === "true") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === "false") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setBool(key, value) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(key, value ? "true" : "false");
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
window.workTrackerTheme.init();
|
window.workTrackerTheme.init();
|
||||||
Loading…
Add table
Add a link
Reference in a new issue