Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Privacy Policy #906

Merged
merged 18 commits into from
Jul 4, 2024
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,
}),
};
Expand Down Expand Up @@ -47,6 +50,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 @@ -60,7 +74,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
Loading