From 7389187bdbc664a5cdd9b2d8b5f947c63e2de925 Mon Sep 17 00:00:00 2001 From: rrrockey Date: Mon, 13 Apr 2026 16:49:54 -0500 Subject: [PATCH 1/4] refactor: update hardcoded localStorage keys to unified variable --- CulinaryCommandApp/Services/LocationService.cs | 2 +- CulinaryCommandApp/Services/LocationState.cs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CulinaryCommandApp/Services/LocationService.cs b/CulinaryCommandApp/Services/LocationService.cs index d81e2b9..db261b8 100644 --- a/CulinaryCommandApp/Services/LocationService.cs +++ b/CulinaryCommandApp/Services/LocationService.cs @@ -255,7 +255,7 @@ public async Task LoadAndPersistLocationsAsync(int userId) if (_locationState.CurrentLocation != null) { await _js.InvokeVoidAsync("localStorage.setItem", - "cc_activeLocationId", + LocationState.ActiveLocStorageKey, _locationState.CurrentLocation.Id); } } diff --git a/CulinaryCommandApp/Services/LocationState.cs b/CulinaryCommandApp/Services/LocationState.cs index 06cfaaf..537374a 100644 --- a/CulinaryCommandApp/Services/LocationState.cs +++ b/CulinaryCommandApp/Services/LocationState.cs @@ -6,6 +6,7 @@ namespace CulinaryCommand.Services { public class LocationState { + public const string ActiveLocStorageKey = "cc_activeLocationId"; private readonly IJSRuntime _js; public List ManagedLocations { get; private set; } = new(); public Location? CurrentLocation { get; private set; } @@ -23,7 +24,7 @@ public async Task HydrateAsync() { if (CurrentLocation != null) return; // Already have it - var savedId = await _js.InvokeAsync("localStorage.getItem", "cc_selected_location_id"); + var savedId = await _js.InvokeAsync("localStorage.getItem", ActiveLocStorageKey); if (!string.IsNullOrEmpty(savedId) && int.TryParse(savedId, out int id)) { @@ -40,7 +41,7 @@ public async Task SetLocationsAsync(List? locations) string? savedId = null; try { - savedId = await _js.InvokeAsync("localStorage.getItem", "cc_activeLocationId"); + savedId = await _js.InvokeAsync("localStorage.getItem", ActiveLocStorageKey); } catch (InvalidOperationException) { @@ -65,9 +66,9 @@ public async Task SetCurrentLocationAsync(Location? loc) try { if (loc is null) - await _js.InvokeVoidAsync("localStorage.removeItem", "cc_activeLocationId"); + await _js.InvokeVoidAsync("localStorage.removeItem", ActiveLocStorageKey); else - await _js.InvokeVoidAsync("localStorage.setItem", "cc_activeLocationId", loc.Id.ToString()); + await _js.InvokeVoidAsync("localStorage.setItem", ActiveLocStorageKey, loc.Id.ToString()); } catch (InvalidOperationException) { From 3c22028ea5364743a499cb602e7c5ffcb88b5b65 Mon Sep 17 00:00:00 2001 From: rrrockey Date: Tue, 14 Apr 2026 10:12:00 -0500 Subject: [PATCH 2/4] feat: make LocationState persistent across refresh still need to have less flicker --- CulinaryCommandApp/Components/App.razor | 3 ++- .../Components/Custom/LocationSelector.razor | 5 +++++ .../wwwroot/images/favicon-old.png | Bin 0 -> 1148 bytes CulinaryCommandApp/wwwroot/images/favicon.ico | Bin 0 -> 15406 bytes CulinaryCommandApp/wwwroot/images/favicon.png | Bin 1148 -> 1444 bytes 5 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 CulinaryCommandApp/wwwroot/images/favicon-old.png create mode 100644 CulinaryCommandApp/wwwroot/images/favicon.ico diff --git a/CulinaryCommandApp/Components/App.razor b/CulinaryCommandApp/Components/App.razor index 88e8715..d6eeda2 100644 --- a/CulinaryCommandApp/Components/App.razor +++ b/CulinaryCommandApp/Components/App.razor @@ -13,7 +13,8 @@ - + @* *@ + diff --git a/CulinaryCommandApp/Components/Custom/LocationSelector.razor b/CulinaryCommandApp/Components/Custom/LocationSelector.razor index a3696b2..62e6b2e 100644 --- a/CulinaryCommandApp/Components/Custom/LocationSelector.razor +++ b/CulinaryCommandApp/Components/Custom/LocationSelector.razor @@ -2,6 +2,7 @@ @using CulinaryCommand.Data.Entities @using System.Text.Json @using CulinaryCommand.Services.UserContextSpace +@using System.Numerics @inject ILocationService LocationService @inject LocationState LocationState @@ -83,6 +84,10 @@ try { var json = await JS.InvokeAsync("localStorage.getItem", "cc_locations"); + + var savedId = await JS.InvokeAsync("localStorage.getItem", LocationState.ActiveLocStorageKey); + Location loc = await LocationService.GetLocationByIdAsync(int.Parse(savedId)); + SetLocation(loc); return string.IsNullOrWhiteSpace(json) ? new List() : (JsonSerializer.Deserialize>(json) ?? new List()); diff --git a/CulinaryCommandApp/wwwroot/images/favicon-old.png b/CulinaryCommandApp/wwwroot/images/favicon-old.png new file mode 100644 index 0000000000000000000000000000000000000000..8422b59695935d180d11d5dbe99653e711097819 GIT binary patch literal 1148 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 literal 0 HcmV?d00001 diff --git a/CulinaryCommandApp/wwwroot/images/favicon.png b/CulinaryCommandApp/wwwroot/images/favicon.png index 8422b59695935d180d11d5dbe99653e711097819..b26b1ae6edd2159be8975051b89e232cfb04c61c 100644 GIT binary patch delta 1427 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 Date: Tue, 14 Apr 2026 13:12:20 -0500 Subject: [PATCH 3/4] feat: finalize LocationState fix and add favicon support --- CulinaryCommandApp/Components/App.razor | 4 +-- .../Components/Custom/LocationSelector.razor | 29 ++++++++++++------ .../wwwroot/images/cc_favicon_black2.png | Bin 0 -> 1078 bytes .../images/cc_favicon_green_clear2.png | Bin 0 -> 1701 bytes CulinaryCommandApp/wwwroot/images/favicon.png | Bin 1444 -> 0 bytes 5 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 CulinaryCommandApp/wwwroot/images/cc_favicon_black2.png create mode 100644 CulinaryCommandApp/wwwroot/images/cc_favicon_green_clear2.png delete mode 100644 CulinaryCommandApp/wwwroot/images/favicon.png diff --git a/CulinaryCommandApp/Components/App.razor b/CulinaryCommandApp/Components/App.razor index d6eeda2..ac942af 100644 --- a/CulinaryCommandApp/Components/App.razor +++ b/CulinaryCommandApp/Components/App.razor @@ -13,8 +13,8 @@ - @* *@ - + + @* *@ diff --git a/CulinaryCommandApp/Components/Custom/LocationSelector.razor b/CulinaryCommandApp/Components/Custom/LocationSelector.razor index 62e6b2e..be2c064 100644 --- a/CulinaryCommandApp/Components/Custom/LocationSelector.razor +++ b/CulinaryCommandApp/Components/Custom/LocationSelector.razor @@ -60,22 +60,31 @@ @code { private List ManagedLocations { get; set; } = new(); private bool _loadedOnce; + + protected override void OnInitialized() + { + LocationState.OnChange += StateHasChanged; + } + protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender || _loadedOnce) return; _loadedOnce = true; - // 1) Load cached instantly (never fails hard) + // 1) Load cached instantly ManagedLocations = await LoadCachedLocationsAsync(); - if (LocationState.CurrentLocation == null && ManagedLocations.Any()) - await LocationState.SetCurrentLocationAsync(ManagedLocations.First()); + var savedId = await JS.InvokeAsync("localStorage.getItem", LocationState.ActiveLocStorageKey); + var savedLocation = int.TryParse(savedId, out var id) + ? ManagedLocations.FirstOrDefault(l => l.Id == id) + : null; + + await LocationState.SetCurrentLocationAsync(savedLocation); StateHasChanged(); - // 2) Load fresh server data if we can resolve user context + // 2) Load fresh server data after await LoadLocationsFromServerAsync(); - StateHasChanged(); } @@ -84,10 +93,7 @@ try { var json = await JS.InvokeAsync("localStorage.getItem", "cc_locations"); - - var savedId = await JS.InvokeAsync("localStorage.getItem", LocationState.ActiveLocStorageKey); - Location loc = await LocationService.GetLocationByIdAsync(int.Parse(savedId)); - SetLocation(loc); + return string.IsNullOrWhiteSpace(json) ? new List() : (JsonSerializer.Deserialize>(json) ?? new List()); @@ -144,4 +150,9 @@ { NavigationManager.NavigateTo($"/settings/locations/{location.Id}"); } + + public void Dispose() + { + LocationState.OnChange -= StateHasChanged; + } } diff --git a/CulinaryCommandApp/wwwroot/images/cc_favicon_black2.png b/CulinaryCommandApp/wwwroot/images/cc_favicon_black2.png new file mode 100644 index 0000000000000000000000000000000000000000..9ac1dcb0ed8b2d544db08c0c9e32c71c952b6461 GIT binary patch literal 1078 zcmV-61j+k}P)d3-uv!*^TCh%?mg#x=R4}Ni{20k-ORs)_!$A-?&dicet^bM2_Hbu(0+zzSGbVHh%5%YfTAD6YS;6e1a~6J-GxOk zBYd~to244il!2q5Gh79oZ8-c5`oXmn#cP6rH+en}e-<(#x&v=8U=?UYROawuUIB%V z(|!t?!7Nx%i~;Y^c^M=f%cr!xUPvMB9>q*J0DTMf&rQ~!j^9E<(7U(5*I^~oc|IEy z8D^UcDD4v_Hz)iKm*Eg>0CUDYk_#gnI)P{Ic{_Pd3_(}Z25LZ`NJ}^#!<85#Z}V*} zxYKohqyewOSDWH zO~dAeByr-}pj&rs9I72s|Ufhu>vt#}yBUJk6U%tyh8U`;TWG&IX z6c&RiIx6~*JE2rKu?6G_=mmyLsp9$m1(s}mpgkmILU+fgTc`n6u9v{@SXt`qjOz%$ zgz@k4G^r)YY#JWseYxm0Yq?E*TXVUkqK^_64L3iNijvJ~ftviv=ec>|RLs>IVQ={TBG1Y2OlYsmWF^dQh?>^B z!Pa~O9^`|!TUVbZ9+!R-S8$TXxnjfAdxG`G!ln$1)_$*6E8y)IO>X;kFlC!NvWm&c z2#bo&J}~a`F@^?r!lY6SrsC6>Tud{-b4sg@Sq(8IzYj;i z%Z%l?F5|`-@CqG_h!bGE)>m}o0l|nRQDt!kbfD9(U^&(6|EY%s=8bdk5LALkdXK~z zpd+3Kz1C~CcS04I>#g+`855DE)$d+7jEJ*f8aBhZd)@`#10CA-=HN}KpaFJR4R3{> z?u14q-Ik*|X(EF(r8KolkA)F>8IRlQspv7K#1K+>qzsLw7bSX;^qQCHzjOB9zr7EGj~Jbuo#fKJ z8#sA08xLwKpu(tNx4r^<%@_O+L03~- zYMuYdEo6V*DUO7{y%+Y(k5Gs$*9E`c%Oih2xl4nLfv8oC9l5E{RMWtN=t~%CFjy|I zcWNj(P6M=;nmPpE^D$6=fI<>o4DMDvBtB_jD6TG-^7X>;vyriUN4J2DEzQI-(isin zX8h#=785#~U2}BNG+%Pr3P>yf6ehE$x;>e)%n8ziTmdg9b(oGKZd)E+)~~ z@wWAVY5yToYq^Q{18AH3I;@|*@|~ejA|ft(mf>b)3G^u#>sx*8K5|L0LECTLc&S@d zS5-r(({jYP2X$G?ynNL}hHS7y>zg+C*)2lif=DTFL0u)W-s(zi+L1Ir3cmIW?-&{>na`--&3Fl7AXIc=0i)4L2yU#);Qn*&UB`jE(=@)s9H|X1-y+r{n8RS+0((z%N2<>ca)IlF4dihC zPw;bC+^xtISCtZ*Sa+zas6m)m1PwI}4)aNU75OH~7Y}L$P^C5G=Ek!a^SKqnxb9s^ zF5b_>-g%K&YiOZz+jaES z)>BC0QSB3AZe-fUj!nO~oc;9FM(~+Dr(2ASf^#(UHe!N_H5hT5gcyfS<*HrybYEnKV6`pr@%rTdR1u zj&bY)-YgapuOlH~Qt z4(O+?kB2n^WE5thR@A_K^BhA1*0*N?`?R5&*v8LAt?&iHXZUt)N)P3oCVr>3qJwnG z)f;Qt1z!t3MuSyf>Ch9d$`mwsco~{!T8w{5FQ_L!Q1}7%LPRl^cD~$UZVb&=7 zkLq^c!Y1<5Nl@mtce}7XJBkPx6$) zlA2%@Z9wouG)jcXUXy~E*7iLnQ2F8+F^iZ6LVx!+=V16iGsOhht8`29B^OGr!+Nj< z4tvFdp`K#Jr}*zOl+`{)<;!X`P|c9MZliTy6@9dHz`lx1>7&GwK3pseO}M!P{xPl@ zG5u^X%44oVMaJ7v=IPE+xt&Ah_Wv4NX8R*zwx7(sWKObf;L!qgzWBFK<}lpQ6onfy z<;Id+|4Q0h$<8Z>!7nYO&u&$i4;YG3gDo*)pczaIjA5YD7n(FxJ32ccl)OT9({l*w vt58Z^B%p0P`@R@XwLXC6yMb;$x%>PB?980~dM>R#00000NkvXXu0mjf*iAWb literal 0 HcmV?d00001 diff --git a/CulinaryCommandApp/wwwroot/images/favicon.png b/CulinaryCommandApp/wwwroot/images/favicon.png deleted file mode 100644 index b26b1ae6edd2159be8975051b89e232cfb04c61c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1444 zcmV;V1zY-wP)N(R{>;of_n!Nl^FHS}=L!<3k(!33EiEln zQ&U4DBO|1xrA1CoP81v*Os7trB0&(;^t8TAP#3_rZ{H{+B!pU9TSX7?^z@{A_wLc& zy?g%(gjxW8{`^TE9v;-w)3d2_Q&UrFZ*M1CTU)h3s0HBCrAw5Xo6An^?Cc1?j~_oy zzkdCqj*bp0Dk`G4Z{PC&Ha0f&^5sj~v15l?AXEbQ{P{DPo0}7|;O_3u9N4~nyPWf- zr6r1ujpbJWi;s_|;^Jb>0Q~;_o1Q*>%290Hx|KeB_`uF^=$kih2x%6xwY4=mckUe3 z*VpsDiHQj^F)>jILM{U@Uc8{Fs3>~%>XpLAn3x#4ef##N4!?Z)Le|#SG&?&>d3kx1 zoSdvafX9y?lfS<|A)R6t6cj|YwY4fs?c&9YbmPViCM^i5$~Xg)laqAt;6eKS{X4IB zb#*0QUtjw1;|JZndzWTrX83t!WhI4&hi~e$v$K;Xne4oJmJmZe*_ZgI&ev(?pA_5rZSs$JIaBy(oR|pR2>FM#>v9U4o^Yh~#g8#a^yO|q; zqobn)We2nY0RgH=tMY$oM(Oh9%dD61KU}B)wH8qs5g@pwl4werO z4~sS>DDA#|`v|3vS1w4?E@^CRq@<)I%FoZ&^n8xS-rk<~XJ%&7wQJXu`hr4&glEp2 zAwhbm1P`RIf{C(a%NCU&Ah||HMsn*=esOVeTumt{DVr*0Q&SW34YDmrOHYCp3J2;a z9X6wu@87?#QWcd&f<|}b$Po^Ll~7uWT&u>$#?;%}%k5Xp(2~L8*RNl5v^Q_wRGBTY z1rRpKJunGxWd9ha&d8?^XJcVaQH3@L;*m5e?J{MbcoSGR{u8Q zjes%CASi%HOiWaWM*#pd9q9)jzw^{(MU%yUiX=xfq zzH#G)3m2%Qq(s!8Xa*J*7Feq{4iuUog4{xBG0=*c(yJM!VUVV)tBYqm2oOehq!_7& yV~kt4AL8cx>C-2kDFGUvC||q^jBwba%>DyZ#>0*Qs}ZIE0000 Date: Tue, 14 Apr 2026 13:35:38 -0500 Subject: [PATCH 4/4] fix: add LocationState flushing to prevent leak --- .../Components/Custom/LogoutWidget.razor | 8 ++++++++ .../Components/Custom/ProfileDropdown.razor | 11 ++++++++++- CulinaryCommandApp/Services/LocationState.cs | 6 ++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CulinaryCommandApp/Components/Custom/LogoutWidget.razor b/CulinaryCommandApp/Components/Custom/LogoutWidget.razor index 6b9a55c..72ad2e5 100644 --- a/CulinaryCommandApp/Components/Custom/LogoutWidget.razor +++ b/CulinaryCommandApp/Components/Custom/LogoutWidget.razor @@ -1,11 +1,19 @@ @rendermode InteractiveServer @inject NavigationManager Nav +@inject IJSRuntime JS +@inject LocationState LocationState + + @code { private async Task Logout() { + await JS.InvokeVoidAsync("localStorage.clear"); + await JS.InvokeVoidAsync("sessionStorage.clear"); + LocationState.FlushLocationState(); + Nav.NavigateTo("/signin", true); // hard reload } } diff --git a/CulinaryCommandApp/Components/Custom/ProfileDropdown.razor b/CulinaryCommandApp/Components/Custom/ProfileDropdown.razor index e4aba68..e7de7df 100644 --- a/CulinaryCommandApp/Components/Custom/ProfileDropdown.razor +++ b/CulinaryCommandApp/Components/Custom/ProfileDropdown.razor @@ -1,6 +1,9 @@ @using CulinaryCommand.Services @using CulinaryCommand.Services.UserContextSpace @inject IUserContextService UserCtx +@inject IJSRuntime JS +@inject LocationState LocationState + @inject NavigationManager Nav @rendermode InteractiveServer @@ -64,8 +67,14 @@ StateHasChanged(); } + private async Task Logout() + { + await JS.InvokeVoidAsync("localStorage.clear"); + await JS.InvokeVoidAsync("sessionStorage.clear"); + LocationState.FlushLocationState(); - private void Logout() => Nav.NavigateTo("/logout", forceLoad: true); + Nav.NavigateTo("/logout", forceLoad: true); + } diff --git a/CulinaryCommandApp/Services/LocationState.cs b/CulinaryCommandApp/Services/LocationState.cs index 537374a..70fd656 100644 --- a/CulinaryCommandApp/Services/LocationState.cs +++ b/CulinaryCommandApp/Services/LocationState.cs @@ -78,5 +78,11 @@ public async Task SetCurrentLocationAsync(Location? loc) // OnChange?.Invoke(); NotifyStateChanged(); } + + public void FlushLocationState() + { + ManagedLocations = new List(); + CurrentLocation = null; + } } }