Skip to content

Commit

Permalink
Feature: Privacy Policy page and banner (#906)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuli-ferna authored Jul 4, 2024
1 parent 290ce3f commit 66a2623
Show file tree
Hide file tree
Showing 14 changed files with 888 additions and 7 deletions.
41 changes: 40 additions & 1 deletion apps/connect/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion apps/connect/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"dompurify": "^3.0.6",
"mixpanel-browser": "^2.49.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-router-dom": "^6.24.0"
},
"devDependencies": {
"@types/dompurify": "^3.0.5",
Expand Down
20 changes: 17 additions & 3 deletions apps/connect/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import { useQueryParams } from "./hooks/useQueryParams";
import { useFormatAssetParam } from "./hooks/useFormatAssetParam";
import WormholeConnect from "@wormhole-foundation/wormhole-connect";
import { eventHandler } from "./providers/telemetry";
import { useRoutes } from "react-router-dom";
import PrivacyPolicy from "./components/pages/PrivacyPolicy";
import { PrivacyPolicyPath, isPreview } from "./utils/constants";
import Banner from "./components/atoms/Banner";

const defaultConfig: WormholeConnectConfig = {
...wormholeConnectConfig,
...((window.location.origin.includes("preview") ||
window.location.origin.includes("testnet")) && {
...(isPreview && {
eventHandler: eventHandler,
}),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -62,6 +65,17 @@ export default function Root() {
useEffect(() => {
localStorage.setItem("Connect Config", JSON.stringify(config, null, 2));
}, [config]);

const Connect = (
<>
<WormholeConnect config={config} theme={customTheme} />
<Banner />
</>
);
const routes = useRoutes([
{ path: `/`, element: Connect },
{ path: PrivacyPolicyPath, element: <PrivacyPolicy /> },
]);
return (
<>
{versions.map(({ appName, version }, idx) => (
Expand All @@ -75,7 +89,7 @@ export default function Root() {
<NewsBar messages={messages} />
<NavBar />
</div>
<WormholeConnect config={config} theme={customTheme} />
{routes}
</>
);
}
3 changes: 3 additions & 0 deletions apps/connect/src/assets/imgs/arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions apps/connect/src/assets/imgs/cookie.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
95 changes: 95 additions & 0 deletions apps/connect/src/components/atoms/Banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { Button, styled } from "@mui/material";
import { useState } from "react";
import { PrivacyPolicyPath } from "../../utils/constants";
import cookie from "../../assets/imgs/cookie.svg";
import { Link } from "../../utils/styles";
import { Link as RouterLink } from "react-router-dom";

const BannerContainer = styled("div")(({ theme }) => ({
display: "flex",
justifyContent: "center",
alignItems: "center",
position: "fixed",
bottom: 60,
left: 30,
right: 30,
zIndex: 100,
[theme.breakpoints.down("sm")]: {
bottom: 75,
},
}));

const Content = styled("div")(({ theme }) => ({
display: "flex",
justifyContent: "center",
alignItems: "center",
position: "fixed",
padding: 10,
backgroundColor: "#FFFFFF14",
gap: 20,
borderRadius: 12,
margin: 26,
mixBlendMode: "normal",
backdropFilter: "blur(60px)",
[theme.breakpoints.down("sm")]: {
margin: 5,
borderRadius: 0,
},
}));

const CloseButton = styled(Button)(() => ({
color: "#070528",
backgroundColor: "white",
borderRadius: 6,
fontSize: 16,
maxHeight: 28,
minWidth: 67,
textTransform: "capitalize",
"&:hover": {
color: "white",
},
}));
const Banner = () => {
const [showBanner, setShowBanner] = useState(true);

const isNewOrExpired = () => {
const cache = localStorage.getItem("showPrivacyPolicy");
const expirationDate =
new Date(Number(cache)).getTime() + 7 * 24 * 60 * 60 * 1000;
const today = new Date().getTime();
if (!cache || expirationDate < today) {
return true;
}
return false;
};
const handleClose = () => {
setShowBanner(false);
if (isNewOrExpired()) {
const today = new Date();
localStorage.setItem("showPrivacyPolicy", today.getTime().toString());
}
};

if (!isNewOrExpired() || !showBanner) {
return null;
}
return (
<BannerContainer>
<Content>
<img src={cookie} alt="cookie" />
<div>
This website is designed to enhance your experience. By continuing to
use this site, you consent to our{" "}
<Link component={RouterLink} to={PrivacyPolicyPath}>
Privacy Policy
</Link>
</div>
<CloseButton variant="contained" onClick={() => handleClose()}>
Close
</CloseButton>
</Content>
</BannerContainer>
);
};

export default Banner;
88 changes: 88 additions & 0 deletions apps/connect/src/components/atoms/TableOfContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { styled } from "@mui/material";
import { useEffect, useState } from "react";

const TableContainer = styled("div")(({ theme }) => ({
borderLeft: "1px solid #FFFFFF1A",
width: 320,
[theme.breakpoints.down("md")]: {
width: "100%",
},
}));

const TableItem = styled("div")(() => ({
paddingLeft: 20,
marginBottom: 10,
marginTop: 10,
cursor: "pointer",
textTransform: "capitalize",
fontSize: 14,
color: "#9C9DBF",
fontWeight: 500,
marginLeft: -2,
"&:hover": {
color: "white",
borderLeft: "3px solid white",
fontWeight: 600,
},
}));

const Title = styled("p")(() => ({
color: "#9C9DBF",
fontSize: 14,
fontWeight: 500,
}));

interface TableItem {
title: string | null;
active: boolean;
id: string;
}
export default function TableOfContent() {
const [tableOfContent, setTableOfContent] = useState<TableItem[]>([]);
const activeItem = {
fontWeight: 600,
color: "white",
borderLeft: "3px solid white",
};
useEffect(() => {
console.log("TableOfContent", document.querySelectorAll("H2"));
const titles = Array.from(document.querySelectorAll("H2"))
.filter((el) => !!el.children[0].textContent)
.map((el) => {
return { title: el.children[0].textContent, active: false, id: el.id };
});
setTableOfContent(titles);
}, []);
const updateActive = (idx: number) => {
const newTableOfContent = tableOfContent.map((item, index) => {
if (index === idx) {
item.active = true;
setTimeout(() => {
//document.querySelector(`#${item.id}`)?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
const el = document.querySelector(`#${item.id}`) as HTMLElement;
window.scroll({ top: el?.offsetTop || 0, behavior: "smooth" });
}, 100);
} else {
item.active = false;
}
return item;
});
setTableOfContent(newTableOfContent);
};
return (
<div>
<Title>TABLE OF CONTENTS</Title>
<TableContainer>
{tableOfContent.map((item, idx) => (
<TableItem
style={item.active ? activeItem : {}}
key={idx}
onClick={() => updateActive(idx)}
>
{item.title}
</TableItem>
))}
</TableContainer>
</div>
);
}
Loading

0 comments on commit 66a2623

Please sign in to comment.