Skip to content

Commit 2100a9c

Browse files
evavirsedamarc2332
andauthored
feat: add terms&conditions popup (#413)
* add terms&conditions popup * fix ci * fix max-width and button * fix build --------- Co-authored-by: Marc Espin <mespinsanz@gmail.com>
1 parent 4643715 commit 2100a9c

File tree

3 files changed

+111
-1
lines changed

3 files changed

+111
-1
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright (c) 2025 IOTA Stiftung
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import {
5+
Button,
6+
ButtonType,
7+
Checkbox,
8+
Dialog,
9+
DialogBody,
10+
DialogContent,
11+
DialogPosition,
12+
Header,
13+
} from '@iota/apps-ui-kit';
14+
import { useRouter } from 'next/navigation';
15+
import { useState } from 'react';
16+
17+
interface TermsAndConditionsDialogProps {
18+
open: boolean;
19+
onOpenChange: (open: boolean) => void;
20+
}
21+
22+
export function TermsAndConditionsDialog({ open, onOpenChange }: TermsAndConditionsDialogProps) {
23+
const [termsAccepted, setTermsAccepted] = useState(false);
24+
const router = useRouter();
25+
26+
return (
27+
<Dialog open={open} onOpenChange={onOpenChange}>
28+
<DialogContent
29+
containerId="overlay-portal-container"
30+
position={DialogPosition.Center}
31+
isFixedPosition
32+
customWidth="w-full max-w-md md:max-w-2xl xl:max-w-[744px]"
33+
>
34+
<Header title="Terms & Conditions" onClose={() => onOpenChange(false)} />
35+
<DialogBody>
36+
<div className="flex flex-col gap-xl">
37+
<div className="flex flex-col gap-md">
38+
<span className="text-label-md text-names-neutral-70">
39+
Effective Date: Lorem ipsum
40+
</span>
41+
<p className="text-body-md text-names-neutral-92">
42+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas ac
43+
aliquam neque, quis ullamcorper ipsum. Name ac purus a magna
44+
ullamcorper venenatis ac eu nulla. Integer odio nunc, pretium sed
45+
nibh non, dignissim mattis metus. Donec quis bibendum mi. Donec sed
46+
tortor ullamcorper, tempus urna porta, sollicitudin nulla. Donec
47+
mattis lectus non consectetur sollicitudin. Nunc vel erat sit amet
48+
lectus condimentum fermentum. Vestibulum dapibus eros ut congue
49+
consectetur. Integer laoreet, leo id hendrerit accumsan, nulla
50+
mauris bibendum nisi, id hendrerit erat nunc porttitor erat.
51+
Pellentesque vitae purus ac urna lacinia commodo. In quis nulla
52+
dapibus, mattis metus ac, vulputate arcu. Vestibulum quis velit
53+
risus. Name lacus nisi, lobortis ac tristique eget, viverra ut
54+
libero. Nulla interdum, nibh at egestas fermentum, lorem lectus
55+
consectetur felis, nec rutrum nibh arcu vel lorem. Proin id urna sit
56+
amet odio luctus vulputate vestibulum ut diam.
57+
</p>
58+
</div>
59+
<div className="flex flex-row items-center justify-between">
60+
<Checkbox
61+
name="terms_conditions"
62+
label="I have read, understand, and agree to the Terms of Service"
63+
onCheckedChange={() => setTermsAccepted(true)}
64+
isChecked={termsAccepted}
65+
/>
66+
<Button
67+
onClick={() => router.push('/')}
68+
type={ButtonType.Primary}
69+
disabled={!termsAccepted}
70+
text="Accept"
71+
/>
72+
</div>
73+
</div>
74+
</DialogBody>
75+
</DialogContent>
76+
</Dialog>
77+
);
78+
}

dapp/src/components/layout/Footer.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,38 @@
11
// Copyright (c) 2025 IOTA Stiftung
22
// SPDX-License-Identifier: Apache-2.0
3+
'use client';
4+
35
import Link from 'next/link';
6+
import { useRouter, useSearchParams } from 'next/navigation';
47

8+
import { TermsAndConditionsDialog } from '@/components/dialogs/TermsAndConditionsDialog';
59
import { FOOTER_LEGAL_LINKS, FOOTER_SOCIAL_LINKS } from '@/lib/constants';
610
import { NamesLogoBranded } from '@/public/icons';
711

812
export function Footer() {
13+
const router = useRouter();
14+
const searchParams = useSearchParams();
15+
const modalParam = searchParams.get('modal');
16+
17+
const isTermsOpen = modalParam === 'terms_conditions';
18+
19+
const handleCloseModal = () => {
20+
const params = new URLSearchParams(searchParams.toString());
21+
params.delete('modal');
22+
router.replace(`/?${params.toString()}`, { scroll: false });
23+
};
24+
25+
const handleLegalClick = (e: React.MouseEvent, path: string) => {
26+
const url = new URL(path, window.location.href);
27+
const modal = url.searchParams.get('modal');
28+
if (modal === 'terms_conditions') {
29+
e.preventDefault();
30+
router.replace(path, { scroll: false });
31+
}
32+
};
33+
934
const COPYRIGHT_YEAR = new Date().getFullYear();
35+
1036
return (
1137
<footer className="w-full bg-names-neutral-6 py-lg">
1238
<div className="container flex flex-col sm:flex-row justify-between items-center gap-y-lg">
@@ -21,6 +47,7 @@ export function Footer() {
2147
<Link
2248
key={title}
2349
href={path}
50+
onClick={(e) => handleLegalClick(e, path)}
2451
className="hover:text-names-primary-80 transition-colors duration-200"
2552
>
2653
{title}
@@ -35,6 +62,11 @@ export function Footer() {
3562
))}
3663
</div>
3764
</div>
65+
66+
<TermsAndConditionsDialog
67+
open={isTermsOpen}
68+
onOpenChange={(open) => !open && handleCloseModal()}
69+
/>
3870
</footer>
3971
);
4072
}

dapp/src/lib/constants/routes.constants.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const FOOTER_SOCIAL_LINKS: Route[] = [
3535
export const FOOTER_LEGAL_LINKS: Route[] = [
3636
{
3737
title: 'Terms & Conditions',
38-
path: '',
38+
path: '/?modal=terms_conditions',
3939
},
4040
{
4141
title: 'Privacy Policy',

0 commit comments

Comments
 (0)