Skip to content

Commit

Permalink
feat(dapp): Privacy Policy and Terms of Service (#573)
Browse files Browse the repository at this point in the history
Signed-off-by: Urban Vidovič <[email protected]>
  • Loading branch information
pseudobun authored Mar 4, 2024
1 parent fc4e573 commit 12dc00a
Show file tree
Hide file tree
Showing 8 changed files with 404 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/tidy-rivers-worry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@blockchain-lab-um/dapp': patch
---

Adds terms of service and privacy policy pages.
5 changes: 5 additions & 0 deletions packages/dapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
"@supabase/supabase-js": "^2.38.5",
"@tanstack/react-query": "^5.17.15",
"@tanstack/react-table": "^8.10.7",
"@types/dompurify": "^3.0.5",
"@types/js-cookie": "^3.0.6",
"@types/jsdom": "^21.1.6",
"@veramo/core": "5.6.0",
"@veramo/credential-eip712": "5.6.0",
"@veramo/credential-w3c": "5.6.0",
Expand All @@ -46,6 +48,7 @@
"date-fns": "^2.30.0",
"did-jwt-vc": "^3.2.13",
"did-resolver": "4.1.0",
"dompurify": "^3.0.9",
"encoding": "^0.1.13",
"ens-did-resolver": "^1.0.4",
"ethers": "^6.9.0",
Expand All @@ -56,8 +59,10 @@
"headless-stepper": "^1.9.1",
"html5-qrcode": "^2.3.8",
"js-cookie": "^3.0.5",
"jsdom": "^24.0.0",
"jsonwebtoken": "^9.0.2",
"luxon": "^3.4.3",
"marked": "^12.0.0",
"next": "13.5.6",
"next-intl": "3.4.0",
"next-sitemap": "^4.2.3",
Expand Down
12 changes: 9 additions & 3 deletions packages/dapp/src/app/[locale]/(public)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import PublicFooter from '@/components/PublicFooter';
import PublicNavbar from '@/components/PublicNavbar';

export default async function PublicLayout({
Expand All @@ -6,10 +7,15 @@ export default async function PublicLayout({
children: React.ReactNode;
}) {
return (
<div className="relative min-h-screen px-4 sm:px-12">
<div className="flex min-h-screen flex-col px-4 sm:px-12">
<PublicNavbar />
<div className="flex min-h-screen pt-24">
<div className="flex-1">{children}</div>
<div className="flex flex-1">
<div className="flex flex-1 items-center justify-center overflow-auto">
{children}
</div>
</div>
<div className="relative bottom-0 left-0 right-0 p-6 max-md:hidden sm:px-12">
<PublicFooter setIsMenuOpen={null} />
</div>
</div>
);
Expand Down
55 changes: 55 additions & 0 deletions packages/dapp/src/app/[locale]/(public)/privacy/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import DOMPurify from 'dompurify';
import { JSDOM } from 'jsdom';
import { marked } from 'marked';

const getPrivacyPolicy = async () => {
const renderer = {
heading(text: string, level: number) {
switch (level) {
case 1:
return `
<h${level} class="text-2xl pt-2 font-bold items-center justify-center text-center">
${text}
</h${level}>`;
case 2:
return `
<h${level} class="text-xl font-bold pt-8 pb-2">
${text}
</h${level}>`;
default:
return `<h${level} class="text-lg"> ${text} </h${level}>`;
}
},
blockquote(text: string) {
return `<div class="w-full flex items-center justify-center"><blockquote class="bg-pink-500 rounded-full text-center dark:bg-orange-accent-dark dark:text-navy-blue-900 w-auto inline-block text-white px-4 my-4">${text}</blockquote></div>`;
},
paragraph(text: string) {
return `<p class="text-justify">${text}</p>`;
},
link(href: string, title: string | null | undefined, text: string) {
return `<a class="text-pink-500 dark:text-orange-accent-dark" href="${href}" title="${title}">${text}</a>`;
},
};

marked.use({ renderer });
const markdown = await (
await fetch(
'https://raw.githubusercontent.com/lutralabs/documents/main/privacy-policy.md',
{ cache: 'no-store' }
)
).text();
const { window } = new JSDOM('');
const purify = DOMPurify(window);
const html = purify.sanitize(await marked.parse(markdown));
return html;
};

export default async function Page() {
const pp = await getPrivacyPolicy();
return (
<div
className="h-full w-full max-w-4xl flex-1 flex-col p-6 sm:p-16"
dangerouslySetInnerHTML={{ __html: pp }}
/>
);
}
56 changes: 56 additions & 0 deletions packages/dapp/src/app/[locale]/(public)/tos/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import DOMPurify from 'dompurify';
import { JSDOM } from 'jsdom';
import { marked } from 'marked';

const getTos = async () => {
const renderer = {
heading(text: string, level: number) {
switch (level) {
case 1:
return `
<h${level} class="text-2xl font-bold text-center items-center justify-center pt-2">
${text}
</h${level}>`;
case 2:
return `
<h${level} class="text-xl font-bold pt-8 pb-2">
${text}
</h${level}>`;
default:
return `<h${level} class="text-lg"> ${text} </h${level}>`;
}
},
blockquote(text: string) {
return `<div class="w-full flex items-center justify-center"><blockquote class="bg-pink-500 rounded-full text-center dark:bg-orange-accent-dark dark:text-navy-blue-900 w-auto inline-block text-white px-4 my-4">${text}</blockquote></div>`;
},
paragraph(text: string) {
return `<p class="text-justify">${text}</p>`;
},
link(href: string, title: string | null | undefined, text: string) {
return `<a class="text-pink-500 dark:text-orange-accent-dark" href="${href}" title="${title}">${text}</a>`;
},
};

marked.use({ renderer });
const markdown = await (
await fetch(
'https://raw.githubusercontent.com/lutralabs/documents/main/ToS.md',
{ cache: 'no-store' }
)
).text();
const { window } = new JSDOM('');
const purify = DOMPurify(window);
const html = purify.sanitize(await marked.parse(markdown));

return html;
};

export default async function Page() {
const tos = await getTos();
return (
<div
className="h-full w-full max-w-4xl flex-1 flex-col p-6 sm:p-16"
dangerouslySetInnerHTML={{ __html: tos }}
/>
);
}
38 changes: 38 additions & 0 deletions packages/dapp/src/components/PublicFooter/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use client';

import { Dispatch, SetStateAction } from 'react';
import Link from 'next/link';

interface PublicFooterProps {
setIsMenuOpen: Dispatch<SetStateAction<boolean>> | null | undefined;
}

export default function PublicFooter({ setIsMenuOpen }: PublicFooterProps) {
return (
<footer className="flex h-full w-full flex-1 items-end justify-between text-xs md:text-sm">
<p>&copy; 2024 Lutra Labs</p>
<div className="flex space-x-6 max-sm:flex-col max-sm:space-x-0 max-sm:text-right">
<Link
href="/privacy"
onClick={() => {
if (setIsMenuOpen) {
setIsMenuOpen(false);
}
}}
>
Privacy Policy
</Link>
<Link
href="/tos"
onClick={() => {
if (setIsMenuOpen) {
setIsMenuOpen(false);
}
}}
>
Terms of Service
</Link>
</div>
</footer>
);
}
8 changes: 6 additions & 2 deletions packages/dapp/src/components/PublicNavbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useTranslations } from 'next-intl';

import Button from '@/components//Button';
import MascaLogo from '@/components/MascaLogo';
import PublicFooter from '../PublicFooter';

const INTERNAL_LINKS = [
{
Expand Down Expand Up @@ -44,8 +45,8 @@ const PublicNavbar = () => {
const pathname = usePathname() ?? '/';

return (
<div className="fixed left-0 right-0 top-0 z-50 m-0 flex h-24 w-screen items-center">
<div className="flex flex-1 items-center px-4 sm:px-12">
<div className="z-50 m-0 p-6 sm:px-12">
<div className="flex flex-1 items-center">
<Link href="/" className="focus-visible:outline-none">
<div className="flex">
<MascaLogo />
Expand Down Expand Up @@ -145,6 +146,9 @@ const PublicNavbar = () => {
{t(name)}
</a>
))}
<div className="h-full items-end">
<PublicFooter setIsMenuOpen={setIsMenuOpen} />
</div>
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit 12dc00a

Please sign in to comment.