Skip to content

Commit

Permalink
Cookie consent render logic (#1240)
Browse files Browse the repository at this point in the history
This pr fixes infinite rerendering issue (it was from the parsing error
of cookie value - so I added a unit test to make sure this works. - I
used the solution from this post, feel free to edit if you see any
improvement
https://stackoverflow.com/questions/5142337/read-a-javascript-cookie-by-name)
- also feel free to edit the test, I mainly put it for my dev purpose.

I removed currenwindowurl logic, replaced it with pathname passed from
the layout root. I started making this change and then realized that
this is not the cause of infinite rendering problem, but I think it is
probably safer to depend on the pathname change than location.href since
href can include so many things like query parameters?
  • Loading branch information
snmln authored Nov 4, 2024
2 parents 85742bc + 7061657 commit 0b1a732
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 27 deletions.
29 changes: 10 additions & 19 deletions app/scripts/components/common/cookie-consent/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import React, { useState, useEffect } from 'react';
import { Icon } from '@trussworks/react-uswds';

import {
COOKIE_CONSENT_KEY,
SESSION_KEY,

getCookie
} from './utils';
import { COOKIE_CONSENT_KEY, SESSION_KEY, getCookie } from './utils';
import {
USWDSAlert,
USWDSButton,
Expand All @@ -18,6 +13,7 @@ import './index.scss';
interface CookieConsentProps {
title?: string | undefined;
copy?: string | undefined;
pathname: string;
sessionStart: string | undefined;
setGoogleTagManager: () => void;
}
Expand All @@ -30,6 +26,7 @@ export const CookieConsent = ({
title,
copy,
sessionStart,
pathname,
setGoogleTagManager
}: CookieConsentProps) => {
const [cookieConsentResponded, SetCookieConsentResponded] =
Expand All @@ -51,9 +48,6 @@ export const CookieConsent = ({
)}; path=/; expires=${closeConsent ? '0' : setCookieExpiration()}`;
};

const currentURL =
typeof window !== 'undefined' ? window.location.href : null;

const setSessionData = () => {
if (typeof window !== 'undefined') {
const checkForSessionDate = window.sessionStorage.getItem(SESSION_KEY);
Expand All @@ -62,6 +56,7 @@ export const CookieConsent = ({
}
}
};

useEffect(() => {
if (sessionStart !== 'true' && !cookieConsentResponded) {
setSessionData();
Expand All @@ -74,7 +69,10 @@ export const CookieConsent = ({
if (!cookieConsentResponded && closeConsent) {
setCloseConsent(false);
}
}, [currentURL]);
// to Rerender on route change
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pathname]);

useEffect(() => {
const cookieValue = {
responded: cookieConsentResponded,
Expand All @@ -84,19 +82,12 @@ export const CookieConsent = ({

// Ignoring setcookie for now since it will make infinite rendering
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
cookieConsentResponded,
cookieConsentAnswer,
closeConsent,
getCookie,
setSessionData,
currentURL
]);
}, [cookieConsentResponded, cookieConsentAnswer, closeConsent]);

return (
<div>
{
//Adding debounce to conditional for animation out
// Adding debounce to conditional for animation out
setTimeout(() => {
!cookieConsentResponded;
}, 500) && (
Expand Down
21 changes: 21 additions & 0 deletions app/scripts/components/common/cookie-consent/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { readCookie, COOKIE_CONSENT_KEY } from './utils';

describe('onCookie', () => {
let cookieValue;
beforeEach(() => {
cookieValue = { responded: false, answer: false };
// Mutating docmument cookie property for test
// eslint-disable-next-line fp/no-mutating-methods
Object.defineProperty(window.document, 'cookie', {
writable: true,
value: `CookieConsent={"responded":true,"answer":false}; _somethingelse=GS1.1.17303800; ${COOKIE_CONSENT_KEY}=${JSON.stringify(
cookieValue
)}`
});
});

it('should parse cookie value correctly', () => {
const cookieJsonVal = readCookie(COOKIE_CONSENT_KEY);
expect(JSON.parse(cookieJsonVal)).toMatchObject(cookieValue);
});
});
15 changes: 9 additions & 6 deletions app/scripts/components/common/cookie-consent/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
export const COOKIE_CONSENT_KEY = `veda--CookieConsent`;
export const SESSION_KEY = `veda--NewSession`;

export const readCookie = (name: string): string => {
// Get name followed by anything except a semicolon
const cookiestring = RegExp(name + '=[^;]+').exec(document.cookie);
// Return everything after the equal sign, or an empty string if the cookie name not found
return decodeURIComponent(
cookiestring ? cookiestring.toString().replace(/^[^=]+./, '') : ''
);
};

export const getCookie = (
SetCookieConsentResponded,
SetCookieConsentAnswer,
Expand All @@ -14,9 +23,3 @@ export const getCookie = (
SetCookieConsentAnswer(cookieContents.answer);
}
};
const readCookie = (name) => {
const nameEQ = name + '=';
const attribute = document.cookie.split(';');
const cookie = attribute.find((cookie) => cookie.trim().startsWith(nameEQ));
return cookie ? cookie.substring(nameEQ.length).trim() : null;
};
11 changes: 9 additions & 2 deletions app/scripts/components/common/layout-root/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React, {
useEffect,
useState
} from 'react';
import { Link } from 'react-router-dom';
import { Link, useLocation } from 'react-router-dom';
import { useDeepCompareEffect } from 'use-deep-compare';
import styled from 'styled-components';
import { Outlet } from 'react-router';
Expand Down Expand Up @@ -56,6 +56,8 @@ function LayoutRoot(props: { children?: ReactNode }) {
const { children } = props;
const [sessionStart, setSesstionStart] = useState<string | undefined>();
const sessionItem = window.sessionStorage.getItem(SESSION_KEY);
const { pathname } = useLocation();

useEffect(() => {
!cookieConsentContent && setGoogleTagManager();
sessionItem && setSesstionStart(sessionItem);
Expand All @@ -81,7 +83,11 @@ function LayoutRoot(props: { children?: ReactNode }) {
<NavWrapper
mainNavItems={mainNavItems}
subNavItems={subNavItems}
logo={<Logo linkProperties={{LinkElement: Link, pathAttributeKeyName: 'to'}} />}
logo={
<Logo
linkProperties={{ LinkElement: Link, pathAttributeKeyName: 'to' }}
/>
}
/>
<PageBody id={PAGE_BODY_ID} tabIndex={-1}>
<Outlet />
Expand All @@ -91,6 +97,7 @@ function LayoutRoot(props: { children?: ReactNode }) {
{...cookieConsentContent}
sessionStart={sessionStart}
setGoogleTagManager={setGoogleTagManager}
pathname={pathname}
/>
)}
</PageBody>
Expand Down

0 comments on commit 0b1a732

Please sign in to comment.