Skip to content

Commit 51a85f3

Browse files
authored
Merge pull request #178 from VidetteMakes/merge/sensit-main
Dark Mode Persistence Via User Profiles
2 parents 21f7990 + 2be179f commit 51a85f3

File tree

11 files changed

+1135
-25
lines changed

11 files changed

+1135
-25
lines changed

MESS/MESS.Blazor/Components/Layout/MainLayout.razor

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
@using System.ComponentModel
55
@using MESS.Blazor.Components.Navigator
66
@using MESS.Services.UI.DarkMode
7+
@using MESS.Services.CRUD.ApplicationUser
78
@using Microsoft.AspNetCore.Components.Authorization
89
@inject NavigationManager Navigation
910
@inject AuthenticationStateProvider AuthProvider
1011
@inject DarkModeInstance DarkModeInstance
12+
@inject IApplicationUserService ApplicationUserService
1113

1214
<HeadContent>
1315
<script src="./Scripts/darkmode.js"></script>
@@ -77,7 +79,6 @@
7779
private bool isSidebarOpen = false;
7880
private bool ShowSidebarToggle = true;
7981
private bool ShowDarkModeToggle = true;
80-
private bool isDarkMode = false;
8182

8283
/// <summary>
8384
/// Called by the framework when parameters are set.
@@ -102,6 +103,29 @@
102103
{
103104
DarkModeInstance.PropertyChanged += OnDarkModeChanged;
104105
}
106+
107+
/// <summary>
108+
/// Called after the component renders. On first render, loads the user's dark mode
109+
/// preference from their profile and applies it.
110+
/// </summary>
111+
protected override async Task OnAfterRenderAsync(bool firstRender)
112+
{
113+
if (firstRender)
114+
{
115+
var authState = await AuthProvider.GetAuthenticationStateAsync();
116+
var userName = authState.User.Identity?.Name;
117+
if (!string.IsNullOrEmpty(userName))
118+
{
119+
var user = await ApplicationUserService.GetByUserNameAsync(userName);
120+
if (user != null)
121+
{
122+
DarkModeInstance.Set(user.DarkMode);
123+
await JS.InvokeVoidAsync("setDarkMode", user.DarkMode);
124+
StateHasChanged();
125+
}
126+
}
127+
}
128+
}
105129

106130
private void OnDarkModeChanged(object? sender, PropertyChangedEventArgs e)
107131
{
@@ -126,13 +150,23 @@
126150
}
127151

128152
/// <summary>
129-
/// Toggles dark mode by invoking the JS function and updates the icon.
153+
/// Toggles dark mode, applies it via JS, and saves the preference to the user's profile.
130154
/// </summary>
131155
private async Task ToggleDarkMode()
132156
{
133157
DarkModeInstance.Toggle();
134-
isDarkMode = !isDarkMode;
135-
await JS.InvokeVoidAsync("toggleDarkMode", isDarkMode);
158+
await JS.InvokeVoidAsync("toggleDarkMode");
159+
160+
var authState = await AuthProvider.GetAuthenticationStateAsync();
161+
var userName = authState.User.Identity?.Name;
162+
if (!string.IsNullOrEmpty(userName))
163+
{
164+
var user = await ApplicationUserService.GetByUserNameAsync(userName);
165+
if (user != null)
166+
{
167+
await ApplicationUserService.UpdateDarkModePreferenceAsync(user.Id, DarkModeInstance.IsDarkMode);
168+
}
169+
}
136170
}
137171

138172
/// <summary>

MESS/MESS.Blazor/Components/Pages/Phoebe/MenuBar/MenuBarPhoebe.razor

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
@using MESS.Blazor.Components.Pages.Phoebe.WorkInstruction
55
@using MESS.Blazor.Components.Pages.Phoebe.WorkInstruction.Import
66
@using MESS.Blazor.Components.Pages.Phoebe.WorkInstruction.Export
7+
@using MESS.Services.CRUD.ApplicationUser
78
@using MESS.Services.CRUD.PartDefinitions
89
@using MESS.Services.CRUD.WorkInstructions
910
@using MESS.Services.DTOs.Products.Detail
@@ -15,6 +16,7 @@
1516
@using MESS.Services.UI.WorkInstructionEditor
1617
@inject AuthenticationStateProvider AuthProvider
1718
@inject IJSRuntime JS
19+
@inject IApplicationUserService ApplicationUserService
1820
@inject IWorkInstructionEditorService EditorService
1921
@inject IWorkInstructionService WorkInstructionService
2022
@inject IPartDefinitionService PartDefinitionService
@@ -162,16 +164,19 @@
162164
Visible="@_showExportDialog"
163165
VisibleChanged="@(val => _showExportDialog = val)" />
164166

165-
<ProductAssociationDialog
166-
AllProducts="@Products"
167-
SelectedProducts="@(ActiveDialog.SelectedProductNames)"
168-
SelectedProductsChanged="OnDialogProductsChanged"
169-
IsVisible="@ActiveDialog.IsVisible"
170-
IsVisibleChanged="@(val => ActiveDialog.IsVisible = val)"
171-
HeaderText="@ActiveDialog.HeaderText"
172-
ConfirmButtonText="@ActiveDialog.ConfirmButtonText"
173-
AllowsRenaming="@(ActiveDialog.Type == DialogType.SaveAs)"
174-
OnConfirmed="HandleDialogConfirmed" />
167+
@if (Products is not null)
168+
{
169+
<ProductAssociationDialog
170+
AllProducts="@Products"
171+
SelectedProducts="@(ActiveDialog.SelectedProductNames)"
172+
SelectedProductsChanged="OnDialogProductsChanged"
173+
IsVisible="@ActiveDialog.IsVisible"
174+
IsVisibleChanged="@(val => ActiveDialog.IsVisible = val)"
175+
HeaderText="@ActiveDialog.HeaderText"
176+
ConfirmButtonText="@ActiveDialog.ConfirmButtonText"
177+
AllowsRenaming="@(ActiveDialog.Type == DialogType.SaveAs)"
178+
OnConfirmed="HandleDialogConfirmed" />
179+
}
175180

176181
@code {
177182
private string? ActiveLineOperator { get; set; }
@@ -399,10 +404,20 @@
399404

400405
private async Task ToggleDarkMode()
401406
{
402-
await JS.InvokeVoidAsync("document.body.classList.toggle", "dark-mode");
403-
var isDark = await JS.InvokeAsync<bool>("document.body.classList.contains", "dark-mode");
404-
_darkModeIcon = isDark ? "bi bi-sun" : "bi bi-moon-stars";
405407
DarkModeInstance.Toggle();
408+
_darkModeIcon = DarkModeInstance.IsDarkMode ? "bi bi-sun" : "bi bi-moon-stars";
409+
await JS.InvokeVoidAsync("toggleDarkMode");
410+
411+
var authState = await AuthProvider.GetAuthenticationStateAsync();
412+
var userName = authState.User.Identity?.Name;
413+
if (!string.IsNullOrEmpty(userName))
414+
{
415+
var user = await ApplicationUserService.GetByUserNameAsync(userName);
416+
if (user != null)
417+
{
418+
await ApplicationUserService.UpdateDarkModePreferenceAsync(user.Id, DarkModeInstance.IsDarkMode);
419+
}
420+
}
406421
}
407422

408423
private async Task ToggleSidebar()

MESS/MESS.Blazor/Components/Pages/Phoebe/WorkInstruction/Export/WorkInstructionExportDialog.razor

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@
3232
</FluentDialogBody>
3333

3434
<FluentDialogFooter>
35-
<WorkInstructionExportButton
36-
@ref="_exportButton"
37-
WorkInstruction="WorkInstruction"
38-
OnDownloadComplete="Close"
39-
OnDownloadStateChanged="HandleDownloadStateChanged"
40-
OnProgressChanged="HandleProgressChanged"/>
41-
35+
@if (WorkInstruction is not null)
36+
{
37+
<WorkInstructionExportButton
38+
@ref="_exportButton"
39+
WorkInstruction="WorkInstruction"
40+
OnDownloadComplete="Close"
41+
OnDownloadStateChanged="HandleDownloadStateChanged"
42+
OnProgressChanged="HandleProgressChanged"/>
43+
}
44+
4245
<button type="button"
4346
class="btn btn-sm btn-outline-secondary"
4447
@onclick="CancelExport">

MESS/MESS.Blazor/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@
122122
// Setup FluentUI
123123
builder.Services.AddFluentUIComponents();
124124

125-
builder.Services.AddSingleton<DarkModeInstance>();
125+
builder.Services.AddScoped<DarkModeInstance>();
126126

127127

128128

MESS/MESS.Blazor/wwwroot/Scripts/darkmode.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ window.toggleDarkMode = function () {
172172
applyTheme(manualOverride);
173173
};
174174

175+
window.setDarkMode = function (isDark) {
176+
manualOverride = isDark;
177+
localStorage.setItem("manualDarkMode", isDark ? "dark" : "light");
178+
applyTheme(isDark);
179+
};
180+
175181
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", e => {
176182
currentDark = e.matches;
177183
if (manualOverride === null) {

0 commit comments

Comments
 (0)