Coder Social home page Coder Social logo

bytexdigital / bytexdigital.blazor.components.cookieconsent Goto Github PK

View Code? Open in Web Editor NEW
31.0 5.0 12.0 916 KB

Components for handling GDPR cookie consent

Home Page: https://www.nuget.org/packages/BytexDigital.Blazor.Components.CookieConsent/

License: Apache License 2.0

HTML 16.99% C# 63.00% JavaScript 9.52% CSS 10.49%
blazor blazor-webassembly blazor-wasm blazor-ui blazor-ui-library blazor-ui-components blazor-cookies blazor-gdpr blazor-cookies-consent

bytexdigital.blazor.components.cookieconsent's Introduction

This library offers a simple way to handle GDPR compliant cookie consent concerns in your Blazor WASM/Serverside app.


How to install


Note

The following installation instructions have been split up depending on how you use Blazor.

  • If you use .NET 8 (or higher) Blazor WebApps AND have your <Router> statically rendered (this means the router's or it's parent component rendermode is not explicitly set for example through [RenderModeWebAssembly] or [RenderModeServer]), then follow the first guide.

  • If you use .NET 8 (or higher) Blazor WebApps AND have your <Router> dynamically rendered (this means the router's or it's parent component rendermode is explicitly set for example through [RenderModeWebAssembly] or [RenderModeServer]), then follow the second guide.

  • If you use .NET 7 or prior, then follow the third guide.


🔧 Installation .NET 8 and higher, Blazor Web App

Note

This library is compatible with dynamic Blazor WebAssembly and Server components within one Blazor Web App project. This means that the UI can be rendered in WebAssembly or Server and changes will propagate to all other interactive components regardless of whether they are running on WebAssembly or the Server. Usage of the CookieConsentService is also possible in all interactive components regardless of whether they are running on the server or in WebAssembly. Interactive means they are explicitly rendered either through Blazor Server or Blazor WebAssembly (e.g. with [RenderModeWebAssembly] or [RenderModeServer]) and NOT statically rendered Blazor components.

Install-Package BytexDigital.Blazor.Components.CookieConsent

Requirements

  • Library version 1.1.0 or higher
  • .NET >= 8.0
  • You're using Blazor Web App and your <Router> is rendered statically without a render mode set (no RenderMode attribute set)

Configure in your project

1. Configure your App.razor

First you will have to determine which Blazor implementation should display the Cookie Consent user interface. It can either be rendered with Blazor WebAssembly or Blazor Server.

Note

If you, for example, choose to render in Blazor WebAssembly, the main CookieConsentHandler will need to be configured to render in WebAssembly.

If you're running interactive Blazor Server components in the same project too and wish to be able to interact with the library there as well, for example to perform a CookieConsentCheck, you'll need to add a CookieConsentInitializer to render on the server which will hook everything up to communicate with the client project. If you're not running Blazor Server components or do not need to interact with them there, you can omit this initializer.

The same applies the other way around if you're rendering the UI in Blazor Server and have WebAssembly components interacting with the cookie library, then the handler must be on the server and the initializer on the client.

🅰️ If you choose to render it with Blazor WebAssembly, add the following beneath your router:
<Router AppAssembly="@typeof(App).Assembly">
    ...
</Router>

<!-- Add this -->
<BytexDigital.Blazor.Components.CookieConsent.CookieConsentHandler @rendermode="@RenderMode.WebAssembly" />

<!-- Add this additionally, if you use interactive Blazor Server components aswell and wish to interact with the library on the server too. -->
<BytexDigital.Blazor.Components.CookieConsent.CookieConsentInitializer @rendermode="@RenderMode.Server" />
🅱️ If you choose to render it with Blazor server, add the following instead:
<Router AppAssembly="@typeof(App).Assembly">
    ...
</Router>

<!-- Add this -->
<BytexDigital.Blazor.Components.CookieConsent.CookieConsentHandler @rendermode="@RenderMode.Server" />

<!-- Add this additionally, if you use WebAssembly components aswell and wish to interact with the library on the client too. -->
<BytexDigital.Blazor.Components.CookieConsent.CookieConsentInitializer @rendermode="@RenderMode.WebAssembly" />

2. Add the required CSS

Add the following css include to your App.razor/Host.razor file.

<link rel="stylesheet" href="_content/BytexDigital.Blazor.Components.CookieConsent/styles.min.css" />

3. (Optional) Add the default font used

Installing the font
By default, the components use the following order of fonts

Inter var, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"

Inter is the font used in the screenshots. If you wish the components to use this font, import the inter font by additionally adding the following CSS link:

<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />

4. Register and configure the services in your dependency container

Add the required services in your Program.cs/Startup.cs and configure cookie categories present in your application.

The library implicitly adds a necessary (value of constant CookieCategory.NecessaryCategoryIdentifier) category.


🅰️ If you're rendering the UI with Blazor WebAssembly, the call will have to be made as follows:

In the WebAssembly client project

builder.Services.AddCookieConsent(o =>
{
    // Your configuration
});

Add this additionally in the server project, if you use Blazor Server aswell and wish to interact with the library on the server.

builder.Services.AddCookieConsent(o =>
{
    // The same configuration as on the client! Best to put this lambda in a shared project to reuse to reduce duplication.
}, withUserInterface: false);

🅱️️ If you're rendering the UI with Blazor Server, the call will have to be made as follows:

In the server project

builder.Services.AddCookieConsent(o =>
{
    // Your configuration
});

Add this additionally in the client project, if you use Blazor WebAssembly aswell and wish to interact with the library on the client.

builder.Services.AddCookieConsent(o =>
{
    // The same configuration as on the server! Best to put this lambda in a shared project to reuse to reduce duplication.
}, withUserInterface: false);

Example configuration
builder.Services.AddCookieConsent(o =>
{
    o.Revision = 1;
    o.PolicyUrl = "/cookie-policy";
    
    // Call optional
    o.UseDefaultConsentPrompt(prompt =>
    {
        prompt.Position = ConsentModalPosition.BottomRight;
        prompt.Layout = ConsentModalLayout.Bar;
        prompt.SecondaryActionOpensSettings = false;
        prompt.AcceptAllButtonDisplaysFirst = false;
    });

    o.Categories.Add(new CookieCategory
    {
        TitleText = new()
        {
            ["en"] = "Google Services",
            ["de"] = "Google Dienste"
        },
        DescriptionText = new()
        {
            ["en"] = "Allows the integration and usage of Google services.",
            ["de"] = "Erlaubt die Verwendung von Google Diensten."
        },
        Identifier = "google",
        IsPreselected = true,

        Services = new()
        {
            new CookieCategoryService
            {
                Identifier = "google-maps",
                PolicyUrl = "https://policies.google.com/privacy",
                TitleText = new()
                {
                    ["en"] = "Google Maps",
                    ["de"] = "Google Maps"
                },
                ShowPolicyText = new()
                {
                    ["en"] = "Display policies",
                    ["de"] = "Richtlinien anzeigen"
                }
            },
            new CookieCategoryService
            {
                Identifier = "google-analytics",
                PolicyUrl = "https://policies.google.com/privacy",
                TitleText = new()
                {
                    ["en"] = "Google Analytics",
                    ["de"] = "Google Analytics"
                },
                ShowPolicyText = new()
                {
                    ["en"] = "Display policies",
                    ["de"] = "Richtlinien anzeigen"
                }
            }
        }
    });
});
🔧 Installation .NET 8 and higher, Full WebAssembly or Full Server
Install-Package BytexDigital.Blazor.Components.CookieConsent

Requirements

  • .NET >= 8.0
  • You're using Blazor Web App and your <Router> is dynamically rendered within a Blazor Server or WASM component (This means your <Router> is inside a component that is fulled rendered either with Blazor Server or Blazor WASM (That is the case if there is a [RenderModeWebAssembly] or [RenderModeServer] attribute on the component containing the router or if the component containing the router is rendered with a @rendermode="@RenderMode.WebAssembly" or @rendermode="@RenderMode.Server" attribute))

Configure in your project

1. Configure your App.razor

Add the CookieConsentHandler your App.razor, beneath the Router component, like so:

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(EmptyLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(EmptyLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

<BytexDigital.Blazor.Components.CookieConsent.CookieConsentHandler />

2. Add the required CSS

Add the following css include to your App.razor/Host.razor file.

<link rel="stylesheet" href="_content/BytexDigital.Blazor.Components.CookieConsent/styles.min.css" />

3. (Optional) Add the default font used

Installing the font
By default, the components use the following order of fonts

Inter var, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"

Inter is the font used in the screenshots. If you wish the components to use this font, import the inter font by additionally adding the following CSS link:

<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />

4. Register and configure the services in your dependency container

Add the required services in your Program.cs/Startup.cs and configure cookie categories present in your application. The library implicitly adds a necessary (value of constant CookieCategory.NecessaryCategoryIdentifier) category. For example:

builder.Services.AddCookieConsent(o =>
{
    o.Revision = 1;
    o.PolicyUrl = "/cookie-policy";
    
    // Call optional
    o.UseDefaultConsentPrompt(prompt =>
    {
        prompt.Position = ConsentModalPosition.BottomRight;
        prompt.Layout = ConsentModalLayout.Bar;
        prompt.SecondaryActionOpensSettings = false;
        prompt.AcceptAllButtonDisplaysFirst = false;
    });

    o.Categories.Add(new CookieCategory
    {
        TitleText = new()
        {
            ["en"] = "Google Services",
            ["de"] = "Google Dienste"
        },
        DescriptionText = new()
        {
            ["en"] = "Allows the integration and usage of Google services.",
            ["de"] = "Erlaubt die Verwendung von Google Diensten."
        },
        Identifier = "google",
        IsPreselected = true,

        Services = new()
        {
            new CookieCategoryService
            {
                Identifier = "google-maps",
                PolicyUrl = "https://policies.google.com/privacy",
                TitleText = new()
                {
                    ["en"] = "Google Maps",
                    ["de"] = "Google Maps"
                },
                ShowPolicyText = new()
                {
                    ["en"] = "Display policies",
                    ["de"] = "Richtlinien anzeigen"
                }
            },
            new CookieCategoryService
            {
                Identifier = "google-analytics",
                PolicyUrl = "https://policies.google.com/privacy",
                TitleText = new()
                {
                    ["en"] = "Google Analytics",
                    ["de"] = "Google Analytics"
                },
                ShowPolicyText = new()
                {
                    ["en"] = "Display policies",
                    ["de"] = "Richtlinien anzeigen"
                }
            }
        }
    });
});

5. The library is ready to be used!

Scroll further down to see how you can use the library to conditionally enable/disable Javascript tags in your HTML or show/hide specific content.

🔧 Installation .NET 7 and prior
Install-Package BytexDigital.Blazor.Components.CookieConsent

Requirements

.NET >= 5.0 and < 8.0


Configure in your project

1. Configure your App.razor

Add the CookieConsentHandler your App.razor, beneath the Router component, like so:

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(EmptyLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(EmptyLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

<BytexDigital.Blazor.Components.CookieConsent.CookieConsentHandler />

2. Add the required CSS

Add the following css include to your index.html/_Host.cshtml file.

<link rel="stylesheet" href="_content/BytexDigital.Blazor.Components.CookieConsent/styles.min.css" />

3. (Optional) Add the default font used

Installing the font
By default, the components use the following order of fonts

Inter var, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"

Inter is the font used in the screenshots. If you wish the components to use this font, import the inter font by additionally adding the following CSS link:

<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />

4. Register and configure the services in your dependency container

Add the required services in your Program.cs/Startup.cs and configure cookie categories present in your application. The library implicitly adds a necessary (value of constant CookieCategory.NecessaryCategoryIdentifier) category. For example:

builder.Services.AddCookieConsent(o =>
{
    o.Revision = 1;
    o.PolicyUrl = "/cookie-policy";
    
    // Call optional
    o.UseDefaultConsentPrompt(prompt =>
    {
        prompt.Position = ConsentModalPosition.BottomRight;
        prompt.Layout = ConsentModalLayout.Bar;
        prompt.SecondaryActionOpensSettings = false;
        prompt.AcceptAllButtonDisplaysFirst = false;
    });

    o.Categories.Add(new CookieCategory
    {
        TitleText = new()
        {
            ["en"] = "Google Services",
            ["de"] = "Google Dienste"
        },
        DescriptionText = new()
        {
            ["en"] = "Allows the integration and usage of Google services.",
            ["de"] = "Erlaubt die Verwendung von Google Diensten."
        },
        Identifier = "google",
        IsPreselected = true,

        Services = new()
        {
            new CookieCategoryService
            {
                Identifier = "google-maps",
                PolicyUrl = "https://policies.google.com/privacy",
                TitleText = new()
                {
                    ["en"] = "Google Maps",
                    ["de"] = "Google Maps"
                },
                ShowPolicyText = new()
                {
                    ["en"] = "Display policies",
                    ["de"] = "Richtlinien anzeigen"
                }
            },
            new CookieCategoryService
            {
                Identifier = "google-analytics",
                PolicyUrl = "https://policies.google.com/privacy",
                TitleText = new()
                {
                    ["en"] = "Google Analytics",
                    ["de"] = "Google Analytics"
                },
                ShowPolicyText = new()
                {
                    ["en"] = "Display policies",
                    ["de"] = "Richtlinien anzeigen"
                }
            }
        }
    });
});

5. The library is ready to be used!

Scroll further down to see how you can use the library to conditionally enable/disable Javascript tags in your HTML or show/hide specific content.


Localization

For now, localization is done entirely inside the configuration of the services as seen in the example above. The library ships with default texts in English, German Dutch, French and Spanish.

The library uses the current CurrentCulture by default. Blazor's .AddLocalization(..) will automatically set the current culture. We aim at adding proper support for IStringLocalizer aswell, so that all localization can be done inside resource files instead.


Disabled or blocked JavaScript

The library depends on JavaScript to save and load preferences and to enable HTML script tags. If JavaScript is blocked or not enabled by a browser, the library will not be able to dynamically enable JavaScript tags like <script type="text/plain" data-consent-category="myCategoryName">; They will remain disabled even if given permission by the user. Saving and loading preferences will also not be possible, which means any permissions the user has given will be forgotten if the browser tab is closed and are only valid within the browser tab they were given in.


Customizing colors and font

The default consent prompt and settings modal are customizable to some degree with CSS variables.

Use a CSS rule as follows to overwrite colors and font used. The values shown are the current default values as shown in the screenshots using Tailwind's theme function.

.cc-isolation-container * {
    /* Font used */
    --cc-font-family: Inter var, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";

    /* Accent color for primary button */
    --cc-color-accent: theme(colors.slate.800);

    /* Accent color for primary button when hovered */
    --cc-color-accent-dark: theme(colors.slate.900);

    /* Color for secondary button */
    --cc-color-secondary: theme(colors.gray.200);

    /* Color for secondary button when hovered */
    --cc-color-secondary-dark: theme(colors.gray.300);

    /* Color for links ("Display policy" links within preferences dialogue) */
    --cc-color-link: theme(colors.slate.400);
    
    /* Color for link when hovered */
    --cc-color-link-highlight: theme(colors.blue.500);

    /* Default color for text */
    --cc-color-text: theme(colors.slate.700);

    /* Background color for active category switch */
    --cc-color-switch-active: theme(colors.slate.800);

    /* (Transparent) Color for background when any modal is opened */
    --cc-color-modal-background: theme(colors.gray.800 / 75%);
}

Custom consent prompt and settings modal

You can entirely replace the components that display to ask the user for consent and the settings modal.

First, create a component that inherits from CookieConsentSettingsModalComponentBase/CookieConsentPromptComponentBase.

Then, you must register this component type in the cookie library by creating a custom variant that inherits from CookieConsentPromptVariantBase/CookieConsentPreferencesVariantBase. For example

public class CustomSettingsModalVariant : CookieConsentDefaultSettingsModalVariant
{
    public override Type ComponentType { get; set; } = typeof(YOUR_CUSTOM_COMPONENT);
}

Lastly, you need to register this variant in the AddCookieConsent call.

builder.Services.AddCookieConsent(options =>
{
    // To replace the consent prompt
    options.ConsentPromptVariant = new CustomConsentPromptVariant();
        
    // To replace the settings modal
    options.SettingsModalVariant = new CustomSettingsModalVariant();
    
    // ...
});

Available ways to hide/show content based on cookie preferences

JavaScript tags

If you wish to use services like Google Analytics, you can integrate them with this library the following way. This will make it so the script tags do not get run unless allowed to do so by the user.

  1. Change the script tags type attribute from type="text/javascript" to type"text/plain".
  2. Add the attribute data-consent-category="IDENTIFIER".
  3. Replace IDENTIFIER with the Identifier given to a configured category. In the example given earlier, this could be google.

Blazor Server Important note: It appears as though when using Blazor Server, Javascript-tags require the defer="true" attribute to be set so that the script tag is not removed by Blazor upon load (view issue).

The result should look like so:

<script type="text/plain" data-consent-category="google">
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-XXXXX-Y', 'auto');
    ga('send', 'pageview');
</script>

This Google Analytics script will only load if given permission.


CookieConsentCheck component

You can use the prebuilt component to show content only if given permission in a category. This can be useful for displaying iframes, for example Google Maps or YouTube videos:

<CookieConsentCheck RequiredCategory="google">
    <Allowed>
        <iframe loading="lazy" allowfullscreen src="https://www.google.com/maps/embed/v1/place?q=place_id:ChIJAVkDPzdOqEcRcDteW0YgIQQ&key=..."></iframe>
    </Allowed>
</CookieConsentCheck>

You can customize what this component will render when the given RequiredCategory is not allowed by defining a NotAllowed tag. By default, the component will render this:



Defining something custom to render can be done the following way. It's a good idea to set the Context parameter on the CookieConsentCheck component so you can easily access it's properties inside your custom NotAllowed block (for example the Component.Category property to access the display name of the required category).

<CookieConsentCheck RequiredCategory="google" Context="Component">
    <Allowed>
        <h1>It works!</h1>
    </Allowed>
    <NotAllowed>
        <button @onclick="async () => await Component.AcceptRequiredAsync()">Show it!</button>
    </NotAllowed>
</CookieConsentCheck>

Manually open the preferences modal

Call the following method to show the preferences menu. This could be done from an element inside your footer for example.

ℹ️ In Blazor Web App, this can be done from both WASM and the Server.

CookieConsentService.ShowSettingsModalAsync();

Stop scripts (like Google Analytics) from running if consent is revoked

If you integrate services such as Google Analytics and the user grants consent, scripts might start running in the background. To stop these scripts from executing once the user revokes consent, it is necessary to refresh the page.

To achieve this, you can subscribe to the following event and evaluate whether a specific category consent has been revoked that requires action such as refreshing the page to stop aforementioned scripts:

CookieConsentService.CategoryConsentChanged += (sender, args) =>
{
    if (args.CategoryIdentifier == "google" &&
        args.ChangedTo == ConsentChangedArgs.ConsentChangeType.Revoked &&
        !args.IsInitialChange)
    {
        // Reload the current page with a hard refresh (restart Blazor app).
        NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
    }
};

Check for the cookie consent state in non-interactive Blazor components such as statically rendered Blazor components, Razor pages or controllers

To accomplish this, you need to read the contents of the cookie which contains the cookie consent preferences encoded in Base64.

The easiest way to achieve this is to use the helper package:

Install-Package BytexDigital.Blazor.Components.CookieConsent.AspNetCore

After installation, add the following service registration:

builder.Services.AddCookieConsentHttpContextServices();

Then request the service from the service container, e.g. in a static Blazor component:

[Inject]
public HttpContextCookieConsent CookieConsent { get; set; }

You can then use the service to fetch the CookiePreferences object.

var preferences = CookieConsent.GetCookieConsentPreferences();

bool isAllowed = preferences.IsCategoryAllowed("google");

Checking for scripts to be loaded before interacting with them or rendering content

Sometimes your code may depend on <script> tags having run, which might be dependant on whether their consent category has been enabled by the user (see #javascript-tags). To make your code run when these script tags are enabled, you might try to listen to the CookieConsentService.CategoryConsentChanged and execute your code if the category of these scripts is enabled. However, inside this event handler, it is not guaranteed that the scripts, enabled by the category you're waiting for, have already run and are ready for usage.

To avoid this race condition, you should additionally use CookieConsentService.ScriptLoaded and CookieConsentService.GetLoadedScriptsAsync to determine if a script you need has already been fully loaded and executed in the DOM.

As an example, let's use the Google Maps API. This example assumes you've setup a cookie consent category with the ID google.

First, you need to add the JS script tag to the Google Maps API library into your host file as follows. Pay attention to how we're giving this script tag a special ID to recognize it by, in this case it's google-maps-api.

<script data-consent-category="google"
        data-consent-script-id="google-maps-api"
        src="https://maps.googleapis.com/maps/api/js?key=YOURKEY&v=3" type="text/plain">
</script>

Now, there are two ways you can go about checking if this script is loaded in the browser. One utilizes the CookieConsentService.ScriptLoaded and CookieConsentService.GetLoadedScriptsAsync methods to achieve this, the other utilizes the ready-built component CookieConsentScriptsLoadedCheck which may be usable for you in some scenarios.

🅰️ Manually check for a loaded script

With this script tag added, we can now use the following setup inside a component to only render a map once we both know the category has been accepted by the user and the script has successfully loaded:

// Flag whether we've called into JS to render the map. This flag is used 
// inside our component to conditionally add the map div to the DOM or not.
public bool RenderMap { get; set; }

protected override void OnInitialized()
{
    // Notify us when scripts are loaded by the cookie consent manager
    CookieConsentService.ScriptLoaded += CookieConsentServiceOnScriptLoaded;
    
    // Notify us if a category consent changes
    CookieConsentService.CategoryConsentChanged += CookieConsentServiceOnCategoryConsentChanged;
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (!firstRender) return;

    // Attempt to render the map after first render
    await RenderMapAsync();
}

private async void CookieConsentServiceOnCategoryConsentChanged(object sender, ConsentChangedArgs e)
{
    // Attempt to render it if a category consent changed
    await RenderMapAsync();
}

private async void CookieConsentServiceOnScriptLoaded(object sender, CookieConsentScriptLoadedArgs e)
{
    // Attempt to render it if a script tag was loaded.
    await RenderMapAsync();
}

private async Task RenderMapAsync()
{
    // Get the list of loaded scripts and preferences from the browser.
    var loadedScripts = await CookieConsentService.GetLoadedScriptsAsync();
    var preferences = await CookieConsentService.GetPreferencesAsync();

    // If our google category isn't allowed, don't render the map.
    if (!preferences.IsCategoryAllowed("google"))
    {
        RenderMap = false;
        return;
    }

    // If the google-maps-api script hasn't loaded yet, don't render the map, as a call to the Google Maps JS API will fail!
    if (loadedScripts.All(x => x.Id != "google-maps-api"))
    {
        RenderMap = false;
        return;
    }
    
    // Note for the above: It's important you check both the scripts AND the category consent, as the
    // latter may have been revoked by the user but the scripts are still loaded until the browser tab
    // is refreshed!

    // If all conditions are met but the map is already rendered, don't render it twice.
    if (RenderMap) return;

    // Call into the UI thread to...
    await InvokeAsync(async () =>
    {
        // ...call into JavaScript to render the map since we know we're both allowed to and the Google Maps API script tag has loaded!
        var module = await JsRuntime.InvokeAsync<IJSObjectReference>("import", "./app.js");
        await module.InvokeVoidAsync("renderMap");
    });
}
🅱️ Use the *CookieConsentScriptsLoadedCheck* component to conditionally render other components

Another way to achieve the same result is utilizing the CookieConsentScriptsLoadedCheck component.

In this case, the above example would look as follows:

<BytexDigital.Blazor.Components.CookieConsent.CookieConsentScriptsLoadedCheck Category="google" Scripts='new [] { "google-maps-api" }' OnRenderStateChanged="RenderMapAsync">
    <div>
        <!-- my map div -->
    </div>
</BytexDigital.Blazor.Components.CookieConsent.CookieConsentScriptsLoadedCheck>
// Will run every time the div went from hidden to shown or vice versa.
async Task RenderMapAsync(bool isShown)
{
    if (isShown) {
        // ...call into JavaScript to render the map since we know we're both allowed to and the Google Maps API script tag has loaded!
        var module = await JsRuntime.InvokeAsync<IJSObjectReference>("import", "./app.js");
        await module.InvokeVoidAsync("renderMap");
    }
}

Changelog

1.2.0

  • Adds event CookieConsentService.ScriptLoaded to execute code when script tags have been loaded dynamically by the cookie consent manager
  • Adds component CookieConsentScriptsLoadedCheck that can be used to conditionally render content depending on whether scripts have been loaded by the cookie consent manager

1.1.0

  • Support for .NET 8 Blazor Web Apps with mixed WebAssembly and Server usage
  • The settings/preferences modal is now replaceable just like the consent prompt is
  • Various internal improvements

1.0.18

Click to expand!
  • Bug fixes

1.0.17

Click to expand!
  • Implemented way to use custom consent prompts components instead of the default one
  • Improved default consent prompt behavior on mobile devices
  • Overall css improvements

1.0.16

Click to expand!
  • Implemented way to customize some colors aswell as the font using CSS variables

1.0.15

Click to expand!
  • Fixed crashes related to JavaScript being not enabled or blocked by browsers ( see #12)

1.0.13

Click to expand!
  • (#11) Added languages ES, FR

1.0.12

Click to expand!
  • (#10) Added language NL

1.0.11

Click to expand!
  • Fixed conditional script tags not being executed after activation in Firefox ( see #9)

1.0.10

Click to expand!
  • (#8) Fixed preferences being saved with revision set to -1

1.0.9

Click to expand!
  • Implemented CSS reset to isolate the components of this library from any other CSS influence

1.0.6

Click to expand!
  • Improved support for overwriting of font used

bytexdigital.blazor.components.cookieconsent's People

Contributors

emorell96 avatar maatj05 avatar ryantt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

bytexdigital.blazor.components.cookieconsent's Issues

CookiePolicyOptions and AddCookieConsent

Just before adding services.AddCookieConsent(...) I am doing:

services.Configure<CookiePolicyOptions>(options =>
{
	options.CheckConsentNeeded = context => true;
	options.MinimumSameSitePolicy = SameSiteMode.None;
	options.Secure = CookieSecurePolicy.Always;
});

Do I still need options.CheckConsentNeeded = context => true; ?

Showing sites privacy policy when clicked

How can i show my privacy policy page when clicked ?
currently i have the privacypolicy.razor page so hopping to navigate to it using Navmanager.NavigateTo('')
In case the privacy policy page is inside www root as .html, also support navigating to that html page as well as you are doing in google-maps privacy policy.

Also can i also add another link to display terms and condition ?

image

UseDefaultConsentPrompt not found?

I have a Blazor server-side app with NET7.

I added the following to my Startup.cs:

services.AddCookieConsent(options =>
{
	options.Revision = 1;
	options.PolicyUrl = "/cookie-policy";

	options.UseDefaultConsentPrompt(prompt =>
	{
		prompt.Position = ConsentModalPosition.BottomRight;
		prompt.Layout = ConsentModalLayout.Bar;
		prompt.SecondaryActionOpensSettings = false;
		prompt.AcceptAllButtonDisplaysFirst = false;
	});
});

UseDefaultConsentPrompt is not found in any namespace. Where is actually located?

Support Blazor-Web-App .NET 8

Hey!

I am testing out the .NET 8 preview 6 for Blazor Web App at the moment and i wanted to test your cookie consent nuget.

Sadly it does not seem to work out of the box and no cookie consent will open. Neither automaticly nor via the CookieConsentService.
The only differece between Blazor Server and Blazor Web App i could spot is that in the Blazor Server project the cookieconsent.js file gets loaded while the Blazor Web App does not seem to load the js file.

But i cant seem to find any error in the console etc. it just does not show up.

Also just a side note:
It seems like if a package.json file already exists in a project your nuget will not add code to it.

Maybe you can have a look so we can enjoy your nuget in the upcoming release of .NET 8

Thanks!

customize order of OpenPreferences and AcceptAll buttons

Would you be able to introduce a way to customize the order of the OpenPreferences and AcceptAll buttons? I would like to display the "AcceptAll" button to be above the "OpenPreferences" button.

I am using version 1.0.17-preview.1673626511

ConsentDescriptionText appears twice

I am using the "Latest prerelease 1.0.17-preview.1673483543" version:

In my .NET 7 Blazor WASM app, the ConsentDescriptionText appears twice:
image

I also tried adding o.ConsentDescriptionText = new Dictionary<string, string> { { "ConsentDescription", "Blah blah." } }; but then it shows "Blah blah. Blah blah."

My Program.cs file:

builder.Services.AddCookieConsent(o =>
{
    o.Revision = 1;
    o.PolicyUrl = "/cookie-policy";
    o.ConsentModalPosition = ConsentModalPosition.BottomRight;
    o.ConsentModalLayout = ConsentModalLayout.Cloud;
    o.ConsentSecondaryActionOpensSettings = true;
    o.Categories.Add(new CookieCategory
    {
        TitleText = new()
        {
            ["en"] = "Google Services",
            ["de"] = "Google Dienste"
        },
        DescriptionText = new()
        {
            ["en"] = "Allows the integration and usage of Google services.",
            ["de"] = "Erlaubt die Verwendung von Google Diensten."
        },
        Identifier = "google",
        IsPreselected = true,

        Services = new()
        {
            new CookieCategoryService
            {
                Identifier = "google-maps",
                PolicyUrl = "https://policies.google.com/privacy",
                TitleText = new()
                {
                    ["en"] = "Google Maps",
                    ["de"] = "Google Maps"
                },
                ShowPolicyText = new()
                {
                    ["en"] = "Display policies",
                    ["de"] = "Richtlinien anzeigen"
                }
            },
            new CookieCategoryService
            {
                Identifier = "google-places",
                PolicyUrl = "https://policies.google.com/privacy",
                TitleText = new()
                {
                    ["en"] = "Google Places",
                    ["de"] = "Google Places"
                },
                ShowPolicyText = new()
                {
                    ["en"] = "Display policies",
                    ["de"] = "Richtlinien anzeigen"
                }
            },
            new CookieCategoryService
            {
                Identifier = "google-analytics",
                PolicyUrl = "https://policies.google.com/privacy",
                TitleText = new()
                {
                    ["en"] = "Google Analytics",
                    ["de"] = "Google Analytics"
                },
                ShowPolicyText = new()
                {
                    ["en"] = "Display policies",
                    ["de"] = "Richtlinien anzeigen"
                }
            }
        }
    });
});

Component crashes if cookieconsent.js is blocked

We have just deployed the (otherwise excellent) Cookie Consent on our site and one of our developers noticed the site crashes for him when he clicks on one of the cookie consent dialog buttons. It tries to call some javascript function and crashes. In this specific case it is due to the user having cookie script blocking turned on. Javascript is not blocked but some scripts are blocked.

Screenshot:

image

Stacktrace:

blazor.server.js:1 [2022-07-06T15:38:41.900Z] Error: Microsoft.JSInterop.JSException: Failed to fetch dynamically imported module: http://localhost:8000/_content/BytexDigital.Blazor.Components.CookieConsent/cookieconsent.js
TypeError: Failed to fetch dynamically imported module: http://localhost:8000/_content/BytexDigital.Blazor.Components.CookieConsent/cookieconsent.js
   at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
   at BytexDigital.Blazor.Components.CookieConsent.CookieConsentService.SavePreferencesAsync(CookiePreferences cookiePreferences)
   at BytexDigital.Blazor.Components.CookieConsent.CookieConsentService.SavePreferencesNecessaryOnlyAsync()
   at BytexDigital.Blazor.Components.CookieConsent.CookieConsentHandler.AcceptAsync(Boolean all)
   at BytexDigital.Blazor.Components.CookieConsent.CookieConsentHandler.<BuildRenderTree>b__38_1()
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.Render

So perhaps the component could use error handling in the case a javascript is not available and respond gracefully (for example ignore it).

As a workaround I have created an <ErrorBoundary> around the CookieConsent-based CookieConsentHandler in App.razor.

Revoke consent manually seems not to disable services

When a user manually revoke given consent via the preferences modal dialog (e.g. the google analytics service), the service seems not to be disabled.
The type of the script remains "text/javascript instead of changing back to "text/plain"
So I guess the consent remains until the user reloads the page.
Is this the expected behaviour or is this some kind of bug?

Issues with Blazor Web App setup

When configuring the .Net 8 blazor web app, following the instructions, I face two issues:

<BytexDigital.Blazor.Components.CookieConsent.CookieConsentInitializer @rendermode="@RenderMode.Server" />

is not found. and, when adding

builder.Services.AddCookieConsent(o =>
{
    // The same configuration as on the server! Best to put this lambda in a shared project to reuse to reduce duplication.
}, withUserInterface: false);

no AddCookieConsent which takes two inputs is found.

Cookie not set in docker

Hello,

this is a fantastic cookie consent banner!
But I encountered two issues I do not know how to fix myself maybe anyone here has an idea.
When using the cookie banner in debug within Visual Studio (Edge browser) everything works as expected, the cookie is set inside the browser on my machine. On another MacOS based machine using Safari no cookie is set, while in chrome it worked.
My main problem is that when running my project inside docker, the cookie banner cookie is never set inside Edge (potentially others too).

Cookie not saving on production

Hi!

The Consent is working perfectly on localhost, but when I publish and use it live it doest not save the user selection at all, and keeps poping up everytime.

Am I missing any configuration required to publish? I've followed the step by step exactly as instructed.

french translation incorrect

Here are the correct translations. Otherwise there are very big mistakes.

    o.ConsentDescriptionText["fr"] = "Ce site web utilise des cookies pour améliorer votre visite.";
    o.ConsentAcknowledgeText["fr"] = "Je comprends.";
    o.ConsentTitleText["fr"] = "Utilisation des cookies";
    o.OpenPreferencesText["fr"] = "Préférences";
    o.ConsentAcceptAllText["fr"] = "Tout Accepter";

Redirect if declined

Hi is it possible to redirect user to his homepage if he declined the cookie consent?

Manually open the preferences modal

Hi,

Thank you for this library, it's amazing! I just have a question regarding the manually opening of the preferences modal. It requires a "CookieConsentService" object, which can be declared with a new statement. This new statement requires IJSRuntime which can be injected, but I don't seem to be able to figure out how I should declare the options tag. Could you add an examle of this to the readme please?

Thanks!

Script does not execute in Firefox upon consent

I have integrated your component and tested it in our solution. I quickly ran into the script tag should have the defer attribute set, otherwise Blazor seems to strip out the script tag from head of the server rendered HTML (.NET Core 6 Blazor - server rendered); I am writing this this since it is not clear from your otherwise excellent documentation (but maybe there is another way to handle this I am not aware of).

Once that was done I tested in Microsoft Edge and it seems to work well. I can see the script tag is changed to text/javascript and there is network traffic accessing a Google analytics resource.

However, the same is not true in Firefox (only have 1 add-on installed and it is disabled; also with all blocking turned off in settings). I can observe the cookie is created in Firefox and the script tag is changed when I consent - but the Javascript for the Google analytics tag does not seem to do anything - i.e. no network traffic.

You can check this yourself by just adding this code to the head of the page:

<script type="text/plain" data-consent-category="google" defer="defer">
      alert("google consent detected - but not in Firefox");
</script>

In Edge the alert will show; in Firefox it will not.

Feature Request: Reject all Button

The tendency of cookie banners in the EU and by the GDPR is more and more in the direction that the user must be given the possibility to reject all non-essential cookies.

Please add an option for a "reject all" button that rejects all cookies. Maybe just in the style of the "change preference" button or even without background. Then you could reduce the height of the other two buttons a bit and it should fit from the design point of view.

So far everything runs fine in .NET 8 RC2

How to read the consent level ?

How do i know if user has denied the consent in my Razor Page ?
Is there a way to track via code in .razor page as to what has been accepted and what has been denied ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.