bring-shrubbery / use-cookie-consent

Smol (~1kB gzipped) hook for managing GDPR cookie consent state.
https://use-cookie-consent.js.org
MIT License
403 stars 15 forks source link

Add a cookie-consent-provider #4

Open pixelass opened 3 years ago

pixelass commented 3 years ago

Is your feature request related to a problem? Please describe.

Feature: Cookie Consent Provider

As a Developer, I want to use a context, so that my application has global access to the consent state

Describe the solution you'd like

Add a CookieConsentProvider (react-context).

Describe alternatives you've considered

I made my own Provider/Context.

Feel free to reuse my code as is. It nicely extends your existing API and adds a new hook useCookieConsentProvider.

I could open a PR for this, but probably not any time soon, since I am currently fully stuffed with work.

Example: https://codesandbox.io/s/eager-tree-by1dk Demo: https://by1dk.csb.app/

import React, { createContext, FC, useContext, useMemo } from "react";
import { CookieConsentHookState, useCookieConsent } from "use-cookie-consent";

export const CookieConsentContext = createContext<CookieConsentHookState>({
    consent: {},
    acceptCookies() {
        /**/
    },
    declineAllCookies() {
        /**/
    },
    acceptAllCookies() {
        /**/
    },
    didAcceptAll() {
        return false;
    },
    didDeclineAll() {
        return false;
    },
    cookies: {
        set() {
            return undefined;
        },
        get() {
            return "";
        },
        getAll() {
            return {};
        },
        getJSON() {
            /**/
        },
        getAllJSON() {
            return {};
        },
        remove() {
            /**/
        },
    },
});

export const CookieConsentProvider: FC = ({ children }) => {
    const {
        consent,
        acceptAllCookies,
        declineAllCookies,
        acceptCookies,
        didAcceptAll,
        didDeclineAll,
        cookies,
    } = useCookieConsent();

    const context = useMemo(
        () => ({
            consent,
            acceptAllCookies,
            declineAllCookies,
            acceptCookies,
            didAcceptAll,
            didDeclineAll,
            cookies,
        }),
        [
            consent,
            acceptAllCookies,
            declineAllCookies,
            acceptCookies,
            didAcceptAll,
            didDeclineAll,
            cookies,
        ]
    );

    return (
        <CookieConsentContext.Provider value={context}>{children}</CookieConsentContext.Provider>
    );
};

export const useCookieConsentContext = () => useContext(CookieConsentContext);

Additional context I use the provider like this

import React from "react";
import {useCookieConsentContext, CookieConsentProvider} from "./CookieConsent";

export const CookieBanner = () => {
  const {acceptAllCookies, declineAllCookies, acceptCookies} = useCookieConsentContext();

  return (
    <div>
      <button onClick={acceptAllCookies}>Accept all</button>
      <button onClick={() => acceptCookies({thirdParty: true})}>
        Accept third-party
      </button>
      <button onClick={() => acceptCookies({firstParty: true})}>
        Accept first-party
      </button>
      <button onClick={declineAllCookies}>Reject all</button>
    </div>
  );
};

export const Cookies = () => {
  const {consent} = useCookieConsentContext();

  return (
    <div>
      <div>
        {`Third-party cookies ${consent.thirdParty ? 'approved' : 'rejected'}`}
      </div>
      <div>
        {`First-party cookies ${consent.firstParty ? 'approved' : 'rejected'}`}
      </div>

    </div>
  );
};

export default function App() {
  return (

      <CookieConsentProvider>
        <CookieBanner/>
        <Cookies/>
      </CookieConsentProvider>
  );
}
bring-shrubbery commented 3 years ago

I would argue that the use of context is unnecessary. The state is stored in cookies (as "necessary" cookies) and you can use useCookieConsent hook from anywhere and it will use the same consent state from any place in your app.

One reason I see why to use context is to have multiple cookie consent "stores", but not sure if that's needed since you usually have just one cookie consent dialog. I'd love to be proved wrong though 😄

bring-shrubbery commented 3 years ago

@pixelass Any argument against the one I presented?

pixelass commented 3 years ago

@bring-shrubbery I had several issues without a context (not 100% sure which) but I might have just been thinking too complicated. AFAIK I wasn't getting the correct state when using the hook in different components/level of the application we're building. ATM I'm very busy and we currently have a different focus but I will report back when I have time to look into refactoring this.

Edit: If I remember correctly the issue was that when adjusting the consent from one component, then the other component would not be informed since only the cookie itself was adjusted but the hook doesn't listen to changes of the cookies.

bring-shrubbery commented 3 years ago

@pixelass Oh yes, that's definitely something we want to have then. I haven't had much time myself, so couldn't look into it properly. I'm happy to either implement your suggested solution myself, or you could send a PR? Both options work for me, just tell me your preference.

I would also add a way of creating your own context instead of having the creation of the context under the hood. That way you could create multiple contexts and prefix the cookies with different prefixes so they don't affect each other.

bring-shrubbery commented 3 years ago

@pixelass This actually might be something for a separate package. Maybe I should create a @use-cookie-consent organization and publish these as scoped packages. Since this package right now is not really using anything that is React related, it could be used as a core package for other packages that are library-specific (@use-cookie-consent/react, @use-cookie-consent/vue, etc)

bring-shrubbery commented 3 years ago

@pixelass I just did that actually 😅 Feel free to add the code for the consent provider to this repo, otherwise I'll put it there in a couple of days 🙂

bring-shrubbery commented 2 years ago

@pixelass The use-cookie-consent-react package now exists and I left the source code empty specifically if you want to add this functionality yourself. You can find it here. If you won't add it this weekend I'll add it myself and try to mark you as an author of that commit 😇

pixelass commented 2 years ago

@bring-shrubbery Thank you. Sadly I won't have time to look into it anytime soon. Feel free to use my code without credit. If I have time I'll be happy to contribute.