Skip to content

Commit 70a136f

Browse files
author
David Warwick
committed
Enhance cookie handling and video playback logic
Refactored `MainLayout.razor` to introduce `_cookiesMode` for tracking user cookie preferences (`AllCookies`, `EssentialOnly`, or none). Improved error handling and added `#if !DEBUG` directives to conditionally load third-party scripts in production. Updated `DemoLanding.razor` to dynamically adjust video playback UI based on third-party consent. Added fallback options for users without consent, including external links and inline playback toggles. Enhanced messaging with `MudAlert` components. Introduced `HasThirdPartyConsent` and `InlinePlaybackEnabled` in `DemoLanding.razor.cs` to manage consent and playback state. Added lifecycle methods (`OnAfterRenderAsync`, `EnableVideoAsync`) for consent handling. Debug-specific logic avoids unnecessary third-party script errors during development. Improved maintainability with code cleanup, reusable patterns, and better state management. Updated YouTube embed URLs for privacy-friendly playback.
1 parent 8911e77 commit 70a136f

File tree

3 files changed

+182
-45
lines changed

3 files changed

+182
-45
lines changed

JwtIdentity.Client/Layout/MainLayout.razor

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
string _theme = "light";
104104
bool _cookiesAccepted = false;
105105
bool _showCookieBanner = false;
106+
string _cookiesMode = string.Empty; // "AllCookies" | "EssentialOnly" | ""
106107
107108
MudTheme MyCustomLightTheme = new MudTheme()
108109
{
@@ -162,9 +163,10 @@
162163
}
163164
await SetTheme();
164165

165-
// Check if cookies have been accepted
166-
var cookiesAccepted = await LocalStorage.GetItemAsync<bool>("cookiesAccepted");
167-
_cookiesAccepted = cookiesAccepted;
166+
// Read cookie preference state
167+
_cookiesAccepted = await LocalStorage.GetItemAsync<bool>("cookiesAccepted");
168+
_cookiesMode = await LocalStorage.GetItemAsStringAsync("cookiesMode") ?? string.Empty;
169+
168170
if (!_cookiesAccepted)
169171
{
170172
// Add a small delay to show the banner after the page loads
@@ -174,11 +176,12 @@
174176
}
175177

176178
bool consentGiven = await JSRuntime.InvokeAsync<bool>("userHasThirdPartyConsent");
179+
#if !DEBUG
177180
if (consentGiven)
178181
{
179182
await JSRuntime.InvokeVoidAsync("loadGoogleAds");
180183
}
181-
184+
#endif
182185
StateHasChanged();
183186
}
184187
catch (Exception ex)
@@ -228,51 +231,78 @@
228231

229232
private async Task AcceptAllCookies()
230233
{
231-
// Save cookie acceptance to local storage
232-
await LocalStorage.SetItemAsync("cookiesAccepted", true);
233-
_cookiesAccepted = true;
234-
_showCookieBanner = false;
235-
236-
// Call our JavaScript function to set the cookie with the API
237-
await JSRuntime.InvokeVoidAsync("acceptAllCookies");
238-
239-
// Load Google Ads once consent is given
240-
await JSRuntime.InvokeVoidAsync("loadGoogleAds");
241-
242-
StateHasChanged();
234+
try
235+
{
236+
// Save cookie acceptance to local storage first
237+
await LocalStorage.SetItemAsync("cookiesAccepted", true);
238+
await LocalStorage.SetItemAsStringAsync("cookiesMode", "AllCookies");
239+
_cookiesAccepted = true;
240+
_cookiesMode = "AllCookies";
241+
_showCookieBanner = false;
242+
243+
// Persist server-side and then (prod) load ads
244+
await JSRuntime.InvokeVoidAsync("acceptAllCookies");
245+
#if !DEBUG
246+
await JSRuntime.InvokeVoidAsync("loadGoogleAds");
247+
#endif
248+
}
249+
catch (Exception ex)
250+
{
251+
Console.Error.WriteLine($"AcceptAllCookies failed: {ex}");
252+
}
253+
finally
254+
{
255+
StateHasChanged();
256+
}
243257
}
244258

245259
private async Task RejectThirdPartyCookies()
246260
{
247-
// First perform a complete cleanup of all third-party services
248-
await JSRuntime.InvokeVoidAsync("clearThirdPartyServicesCompletely");
249-
250-
// Save cookie acceptance to local storage
251-
await LocalStorage.SetItemAsync("cookiesAccepted", true);
252-
_cookiesAccepted = true;
253-
_showCookieBanner = false;
254-
255-
// Call our JavaScript function to set cookie rejection
256-
await JSRuntime.InvokeVoidAsync("rejectThirdPartyCookies");
257-
258-
// Force page reload to ensure a clean state
259-
await JSRuntime.InvokeVoidAsync("eval", "location.reload()");
260-
261-
// Note: The state change below will likely not execute due to the page reload
262-
StateHasChanged();
261+
try
262+
{
263+
// Persist choice to local storage first to survive any JS errors/reloads
264+
await LocalStorage.SetItemAsync("cookiesAccepted", true);
265+
await LocalStorage.SetItemAsStringAsync("cookiesMode", "EssentialOnly");
266+
_cookiesAccepted = true;
267+
_cookiesMode = "EssentialOnly";
268+
_showCookieBanner = false;
269+
270+
// Best-effort cleanup and server notification
271+
try { await JSRuntime.InvokeVoidAsync("clearThirdPartyServicesCompletely"); } catch {}
272+
try { await JSRuntime.InvokeVoidAsync("rejectThirdPartyCookies"); } catch {}
273+
274+
// Force page reload to ensure a clean state
275+
try { await JSRuntime.InvokeVoidAsync("eval", "location.reload()"); } catch {}
276+
}
277+
catch (Exception ex)
278+
{
279+
Console.Error.WriteLine($"RejectThirdPartyCookies failed: {ex}");
280+
}
281+
finally
282+
{
283+
StateHasChanged();
284+
}
263285
}
264286

265287
private async Task OpenCookieSettings()
266288
{
267-
// Clear existing cookie consent from localStorage
268-
await LocalStorage.RemoveItemAsync("cookiesAccepted");
269-
_cookiesAccepted = false;
270-
271-
// Call JavaScript to clear the third-party cookies and consent cookie
272-
await JSRuntime.InvokeVoidAsync("clearCookieConsent");
273-
274-
// Show the cookie banner again
275-
_showCookieBanner = true;
276-
StateHasChanged();
289+
try
290+
{
291+
// Clear existing cookie consent from localStorage
292+
await LocalStorage.RemoveItemAsync("cookiesAccepted");
293+
await LocalStorage.RemoveItemAsync("cookiesMode");
294+
_cookiesAccepted = false;
295+
_cookiesMode = string.Empty;
296+
297+
// Call JavaScript to clear the third-party cookies and consent cookie
298+
try { await JSRuntime.InvokeVoidAsync("clearCookieConsent"); } catch {}
299+
300+
// Show the cookie banner again
301+
_showCookieBanner = true;
302+
}
303+
finally
304+
{
305+
StateHasChanged();
306+
}
277307
}
278308
}

JwtIdentity.Client/Pages/Demo/DemoLanding.razor

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,70 @@
122122

123123
<MudPaper Elevation="1" Class="pa-5 mt-6">
124124
<MudText Typo="Typo.h5" Class="mb-3">Watch the Survey Shark Demo Walkthrough</MudText>
125-
125+
126+
@{
127+
#if DEBUG
128+
if (HasThirdPartyConsent && InlinePlaybackEnabled)
129+
{
126130
<iframe class="video-container"
127-
src="https://www.youtube.com/embed/v0XqRue1aAM"
131+
src="https://www.youtube-nocookie.com/embed/v0XqRue1aAM?rel=0&modestbranding=1&playsinline=1"
128132
title="Survey Shark Demo Video"
129-
frameborder="0"
130133
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
134+
referrerpolicy="strict-origin-when-cross-origin"
135+
loading="lazy"
131136
allowfullscreen>
132137
</iframe>
138+
<div class="mt-2">
139+
<MudButton Variant="Variant.Outlined" Color="Color.Primary" Href="https://www.youtube.com/watch?v=v0XqRue1aAM" Target="_blank" Rel="noopener noreferrer">
140+
Open on YouTube
141+
</MudButton>
142+
</div>
143+
}
144+
else
145+
{
146+
if (!HasThirdPartyConsent)
147+
{
148+
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Class="mb-2">
149+
To watch this video, enable third-party cookies.
150+
</MudAlert>
151+
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="EnableVideoAsync">Enable video</MudButton>
152+
}
153+
else
154+
{
155+
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Class="mb-2">
156+
Third-party cookies enabled. To avoid debug-time script errors, open externally or choose inline playback below.
157+
</MudAlert>
158+
<MudStack Spacing="1">
159+
<MudButton Variant="Variant.Outlined" Color="Color.Secondary" Href="https://www.youtube.com/watch?v=v0XqRue1aAM" Target="_blank" Rel="noopener noreferrer">
160+
Open on YouTube instead
161+
</MudButton>
162+
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="EnableInlinePlaybackAsync">
163+
Play inline (may trigger third-party scripts)
164+
</MudButton>
165+
</MudStack>
166+
}
167+
}
168+
#else
169+
if (HasThirdPartyConsent)
170+
{
171+
<iframe class="video-container"
172+
src="https://www.youtube-nocookie.com/embed/v0XqRue1aAM?rel=0&modestbranding=1&playsinline=1"
173+
title="Survey Shark Demo Video"
174+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
175+
referrerpolicy="strict-origin-when-cross-origin"
176+
loading="lazy"
177+
allowfullscreen>
178+
</iframe>
179+
}
180+
else
181+
{
182+
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Class="mb-2">
183+
To watch this video, enable third-party cookies.
184+
</MudAlert>
185+
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="EnableVideoAsync">Enable video</MudButton>
186+
}
187+
#endif
188+
}
133189

134190
</MudPaper>
135191
</MudContainer>

JwtIdentity.Client/Pages/Demo/DemoLanding.razor.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,62 @@ public class DemoLandingModel : BlazorBase
1111

1212
protected string YoutubeEmbedCode => AppSettings.Youtube?.HomePageCode ?? string.Empty;
1313

14+
protected bool HasThirdPartyConsent { get; set; }
15+
protected bool InlinePlaybackEnabled { get; set; }
16+
1417
protected override async Task OnInitializedAsync()
1518
{
1619
AppSettings = await ApiService.GetPublicAsync<AppSettings>("/api/appsettings");
1720
}
1821

22+
protected override async Task OnAfterRenderAsync(bool firstRender)
23+
{
24+
if (!firstRender)
25+
{
26+
return;
27+
}
28+
29+
try
30+
{
31+
HasThirdPartyConsent = await JSRuntime.InvokeAsync<bool>("userHasThirdPartyConsent");
32+
#if !DEBUG
33+
// In non-DEBUG (production) automatically enable inline playback once consent exists
34+
if (HasThirdPartyConsent)
35+
{
36+
InlinePlaybackEnabled = true;
37+
}
38+
#endif
39+
await InvokeAsync(StateHasChanged);
40+
}
41+
catch
42+
{
43+
// ignore JS interop failures during prerender or debug
44+
}
45+
}
46+
47+
protected async Task EnableVideoAsync()
48+
{
49+
try
50+
{
51+
await JSRuntime.InvokeVoidAsync("setThirdPartyCookieConsent", "AllCookies");
52+
HasThirdPartyConsent = true;
53+
#if !DEBUG
54+
// Auto-enable inline playback in production immediately after consent
55+
InlinePlaybackEnabled = true;
56+
#endif
57+
await InvokeAsync(StateHasChanged);
58+
}
59+
catch { }
60+
}
61+
62+
#if DEBUG
63+
protected Task EnableInlinePlaybackAsync()
64+
{
65+
InlinePlaybackEnabled = true;
66+
return InvokeAsync(StateHasChanged);
67+
}
68+
#endif
69+
1970
protected async Task BeginLinearDemo()
2071
{
2172
if (IsStartingLinearDemo)

0 commit comments

Comments
 (0)