Skip to content

Commit

Permalink
Merge pull request #635 from CodeWritingCow/codewritingcow/597-cookie…
Browse files Browse the repository at this point in the history
…-banner

597: Accept or Decline Cookies
  • Loading branch information
nlebovits committed May 31, 2024
2 parents 2e887c7 + 99a6593 commit 6c6e6c8
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 48 deletions.
2 changes: 1 addition & 1 deletion src/app/(content-pages)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const ContentPagesLayout = ({ children }: { children: React.ReactNode }) => {
<Header />
<main id="main">
<div className="max-w-[68.75rem] mx-auto pb-[30px] pt-[60px] w-[90%]">
{children}
{children}
</div>
</main>
<Footer />
Expand Down
11 changes: 11 additions & 0 deletions src/app/CookieProviderWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use client";

import { CookieProvider } from "@/context/CookieContext";

export const CookieProviderWrapper = ({
children,
}: {
children: React.ReactNode;
}) => {
return <CookieProvider>{children}</CookieProvider>;
};
2 changes: 2 additions & 0 deletions src/app/find-properties/[[...opa_id]]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Header, Hotjar } from "@/components";
import CookieConsentBanner from "@/components/CookieConsentBanner";

export const metadata = {
title: "Find Properties",
Expand All @@ -10,6 +11,7 @@ const MapLayout = ({ children }: { children: React.ReactNode }) => {
<Header />
<main id="main">{children}</main>
<Hotjar />
<CookieConsentBanner />
</div>
);
};
Expand Down
3 changes: 2 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Metadata } from "next";
import "./globals.css";
import { CookieProviderWrapper } from "./CookieProviderWrapper";

export const metadata: Metadata = {
title: {
Expand Down Expand Up @@ -28,7 +29,7 @@ export default function RootLayout({
>
Skip to main content
</a>
{children}
<CookieProviderWrapper>{children}</CookieProviderWrapper>
</body>
</html>
);
Expand Down
53 changes: 53 additions & 0 deletions src/components/CookieConsentBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"use client";

import { ThemeButton } from "./ThemeButton";
import { Check, X } from "@phosphor-icons/react";
import { useCookieContext } from "@/context/CookieContext";

const CookieConsentBanner = () => {
const { shouldShowBanner, setShouldAllowCookies, setShouldShowBanner } =
useCookieContext();

const onClickButton = (shouldSaveCookies: boolean) => {
setShouldAllowCookies(shouldSaveCookies);
setShouldShowBanner(false);
};

return (
<div
className={`${
shouldShowBanner
? "md:flex fixed inset-x-0 bottom-0 z-20 justify-between bg-blue-200 p-4 sm:p-6"
: "hidden"
}`}
>
<div>
<div className="heading-md">Can we store cookies to your browser?</div>
<div className="body-sm">
This provides you a nice experience preserving your filtering, your
position on the map and your property saved list.
</div>
</div>

<div className="flex justify-end gap-2 pt-4 sm:pt-0">
<div className="flex flex-none items-center gap-x-2">
<ThemeButton
color="tertiary"
label="Decline"
startContent={<X />}
onPress={() => onClickButton(false)}
/>

<ThemeButton
color="primary"
label="Accept"
startContent={<Check />}
onPress={() => onClickButton(true)}
/>
</div>
</div>
</div>
);
};

export default CookieConsentBanner;
91 changes: 61 additions & 30 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,63 @@
const Footer = () => (
<div className="flex flex-col">
<footer className="px-6 h-16 flex flex-grow w-full items-center">
<nav className="w-full" aria-label="content info">
<ul className="flex flex-wrap gap-x-4 justify-between items-center w-full backdrop-saturate-150 bg-background/70">
<li>
<span className="base-sm text-gray-600">
© 2024 Clean & Green Philly
</span>
</li>

<li className="base-sm underline text-gray-600 mx-auto">
<a href="/legal-disclaimer" className="hover:text-gray-800">
Legal Disclaimer
</a>
</li>

<li>
<a
href="mailto:[email protected]"
className="base-sm underline text-gray-600 hover:text-gray-800"
>
Contact Us
</a>
</li>
</ul>
</nav>
</footer>
</div>
);
"use client";

import { useCookieContext } from "@/context/CookieContext";
import CookieConsentBanner from "./CookieConsentBanner";
import Link from "next/link";

const Footer = () => {
let { setShouldShowBanner } = useCookieContext();

const onClickCookieSettings = () => {
setShouldShowBanner(true);
};

return (
<div className="flex flex-col">
<footer className="px-6 h-16 flex flex-grow justify-center items-center">
<nav aria-label="content info">
<ul className="flex flex-wrap gap-x-2 justify-between items-center w-full backdrop-saturate-150 bg-background/70">
<li>
<span className="base-sm text-gray-600">
© 2024 Clean & Green Philly
</span>
</li>

<span className="max-sm:hidden"></span>

<li className="base-sm underline text-gray-600 mx-auto">
<a
className="hover:text-gray-800 cursor-pointer"
onClick={onClickCookieSettings}
>
Cookie Settings
</a>
</li>

<span className="max-sm:hidden"></span>

<li className="base-sm underline text-gray-600 mx-auto">
<Link href="/legal-disclaimer" className="hover:text-gray-800">
Legal Disclaimer
</Link>
</li>

<span className="max-sm:hidden"></span>

<li>
<a
href="mailto:[email protected]"
className="base-sm underline text-gray-600 hover:text-gray-800"
>
Contact Us
</a>
</li>
</ul>
</nav>

<CookieConsentBanner />
</footer>
</div>
);
};

export default Footer;
3 changes: 2 additions & 1 deletion src/components/IconLink.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"use client";

import { Button, Link, NavbarItem } from "@nextui-org/react";
import { Button, NavbarItem } from "@nextui-org/react";
import { usePathname } from "next/navigation";
import Link from "next/link";

interface IconLinkProps {
icon: React.ReactElement;
Expand Down
43 changes: 28 additions & 15 deletions src/components/SinglePropertyDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import ContentCard from "./ContentCard";
import cleanup from "@/images/transform-a-property.png";
import { PiEyeSlash } from "react-icons/pi";
import { useFilter } from "@/context/FilterContext";
import { useCookieContext } from "@/context/CookieContext";
import { getPropertyIdsFromLocalStorage } from "@/utilities/localStorage";

interface PropertyDetailProps {
Expand Down Expand Up @@ -61,6 +62,7 @@ const SinglePropertyDetail = ({
const [hover, setHover] = useState<boolean>(false);
const [isPropertySavedToLocalStorage, setIsPropertySavedToLocalStorage] =
useState(false);
let { shouldAllowCookies, setShouldShowBanner } = useCookieContext();

useEffect(() => {
if (!localStorage.getItem("opa_ids")) {
Expand Down Expand Up @@ -139,6 +141,14 @@ const SinglePropertyDetail = ({
};

const onClickSaveButton = () => {
if (shouldAllowCookies) {
findPropertyIdInLocalStorage();
} else {
setShouldShowBanner(true);
}
};

const findPropertyIdInLocalStorage = () => {
const localStorageData = localStorage.getItem("opa_ids");
const parsedLocalStorageData = localStorageData
? JSON.parse(localStorageData)
Expand All @@ -147,27 +157,30 @@ const SinglePropertyDetail = ({
if (parsedLocalStorageData.opa_ids[OPA_ID]) {
removePropertyIdFromLocalStorage(parsedLocalStorageData);
setIsPropertySavedToLocalStorage(false);
dispatchFilterAction(parsedLocalStorageData);
} else {
savePropertyIdToLocalStorage(parsedLocalStorageData);
setIsPropertySavedToLocalStorage(true);
}
};

if (parsedLocalStorageData.count === 0) {
const dispatchFilterAction = (data: any) => {
if (data.count === 0) {
dispatch({
type: "SET_DIMENSIONS",
property: "OPA_ID",
dimensions: [],
});
setShouldFilterSavedProperties(false);
} else {
if (shouldFilterSavedProperties) {
let propertyIds = getPropertyIdsFromLocalStorage();
dispatch({
type: "SET_DIMENSIONS",
property: "OPA_ID",
dimensions: [],
dimensions: [...propertyIds],
});
setShouldFilterSavedProperties(false);
} else {
if (shouldFilterSavedProperties) {
let propertyIds = getPropertyIdsFromLocalStorage();
dispatch({
type: "SET_DIMENSIONS",
property: "OPA_ID",
dimensions: [...propertyIds],
});
}
}
} else {
savePropertyIdToLocalStorage(parsedLocalStorageData);
setIsPropertySavedToLocalStorage(true);
}
};

Expand Down
48 changes: 48 additions & 0 deletions src/context/CookieContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, {
FC,
createContext,
useContext,
useState,
ReactNode,
} from "react";

interface CookieContextProps {
shouldAllowCookies: boolean;
shouldShowBanner: boolean;
setShouldAllowCookies: React.Dispatch<React.SetStateAction<boolean>>;
setShouldShowBanner: React.Dispatch<React.SetStateAction<boolean>>;
}

interface CookieProviderProps {
children: ReactNode;
}

export const CookieContext = createContext<CookieContextProps | undefined>(
undefined
);

export const useCookieContext = () => {
const context = useContext(CookieContext);
if (!context) {
throw new Error("useCookieContext must be used within a CookieProvider");
}
return context;
};

export const CookieProvider: FC<CookieProviderProps> = ({ children }) => {
const [shouldAllowCookies, setShouldAllowCookies] = useState(false);
const [shouldShowBanner, setShouldShowBanner] = useState(true);

return (
<CookieContext.Provider
value={{
shouldAllowCookies,
shouldShowBanner,
setShouldAllowCookies,
setShouldShowBanner,
}}
>
{children}
</CookieContext.Provider>
);
};

0 comments on commit 6c6e6c8

Please sign in to comment.