Skip to content

Commit 9ba2148

Browse files
committed
feat: Added privacy components
1 parent ca3e687 commit 9ba2148

File tree

7 files changed

+190
-12
lines changed

7 files changed

+190
-12
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ dist
1212
dist-ssr
1313
*.local
1414
allcode.txt
15+
docs
1516

1617
# Editor directories and files
1718
.vscode/*
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
'use client';
2+
3+
import React from 'react';
4+
import { SimpleDialog as Dialog, SimpleDialogContent as DialogContent } from '../ui/simple-dialog';
5+
import { Button } from '../ui/button';
6+
import { X, Shield, CheckCircle, Lock, Eye } from 'lucide-react';
7+
8+
interface PrivacyModalProps {
9+
onClose: () => void;
10+
}
11+
12+
const PrivacyModal: React.FC<PrivacyModalProps> = ({ onClose }) => {
13+
// Handler for clicks outside the modal
14+
const handleOutsideClick = (e: React.MouseEvent<HTMLDivElement>) => {
15+
// Only close if the click was directly on the overlay (not on the modal content)
16+
if (e.target === e.currentTarget) {
17+
onClose();
18+
}
19+
};
20+
21+
return (
22+
<div
23+
className='fixed inset-0 z-50 flex items-center justify-center overflow-hidden bg-black/50'
24+
onClick={handleOutsideClick}
25+
>
26+
<div
27+
className='bg-white m-2 sm:m-5 max-w-2xl w-full rounded-lg p-0 overflow-hidden shadow-xl'
28+
onClick={(e) => e.stopPropagation()} // Prevent clicks inside from closing
29+
>
30+
<div className='bg-brand-pink p-2 flex items-center justify-between sm:rounded-t-lg'>
31+
<h2 className='text-xl font-semibold text-white flex items-center'>
32+
<Shield className="mr-2" size={20} />
33+
Privacy & Data Protection
34+
</h2>
35+
<button
36+
className='text-white focus:outline-none focus:ring-2 focus:ring-white rounded-sm'
37+
onClick={onClose}
38+
>
39+
<X size={24} />
40+
</button>
41+
</div>
42+
43+
<div
44+
className='relative overflow-auto max-h-[70vh]'
45+
style={{
46+
background: 'linear-gradient(135deg, #f5f7fa 0%, #f8f9fb 100%)',
47+
}}
48+
>
49+
<div className='p-4 sm:p-6'>
50+
<div className="space-y-6">
51+
{/* How We Protect Your Data */}
52+
<section>
53+
<h3 className="text-lg font-semibold flex items-center text-gray-800 mb-3">
54+
<Lock className="mr-2 text-brand-pink" size={20} />
55+
How We Protect Your Data
56+
</h3>
57+
<div className="bg-white p-4 rounded-lg shadow-sm">
58+
<p className="mb-3 text-gray-700">
59+
At Beacons, we prioritize your privacy and ensure your personal information is handled securely.
60+
</p>
61+
<ul className="list-disc pl-5 space-y-2 text-gray-700">
62+
<li>Your data is encrypted both in transit and at rest</li>
63+
<li>We use secure passwordless authentication (Magic Links) to protect your account</li>
64+
<li>We only collect the minimum information needed to provide our service</li>
65+
<li>You retain complete control over your data at all times</li>
66+
</ul>
67+
</div>
68+
</section>
69+
70+
{/* Your Rights */}
71+
<section>
72+
<h3 className="text-lg font-semibold flex items-center text-gray-800 mb-3">
73+
<CheckCircle className="mr-2 text-brand-pink" size={20} />
74+
Your Rights
75+
</h3>
76+
<div className="bg-white p-4 rounded-lg shadow-sm">
77+
<p className="mb-3 text-gray-700">
78+
Under data protection law, you have the right to:
79+
</p>
80+
<ul className="list-disc pl-5 space-y-2 text-gray-700">
81+
<li>Access your personal data</li>
82+
<li>Correct inaccurate data</li>
83+
<li>Request deletion of your data</li>
84+
<li>Restrict or object to processing of your data</li>
85+
<li>Obtain and reuse your data (data portability)</li>
86+
<li>Withdraw consent at any time</li>
87+
</ul>
88+
</div>
89+
</section>
90+
91+
{/* Data Sharing */}
92+
<section>
93+
<h3 className="text-lg font-semibold flex items-center text-gray-800 mb-3">
94+
<Eye className="mr-2 text-brand-pink" size={20} />
95+
Data Sharing
96+
</h3>
97+
<div className="bg-white p-4 rounded-lg shadow-sm">
98+
<p className="mb-3 text-gray-700">
99+
We only share your data:
100+
</p>
101+
<ul className="list-disc pl-5 space-y-2 text-gray-700">
102+
<li>With your explicit consent</li>
103+
<li>Only statements marked as "public" can be shared with your line manager</li>
104+
<li>You control when and how your data is shared</li>
105+
<li>Email sharing is initiated by you and only sent to the email address you provide</li>
106+
</ul>
107+
</div>
108+
</section>
109+
</div>
110+
111+
<div className="mt-6 flex justify-center">
112+
<Button
113+
variant='outline'
114+
className='px-6'
115+
type='button'
116+
onClick={onClose}
117+
>
118+
<X size={16} className='mr-1.5' />
119+
Close
120+
</Button>
121+
</div>
122+
</div>
123+
</div>
124+
</div>
125+
</div>
126+
);
127+
};
128+
129+
export default PrivacyModal;

src/components/modals/ShareEmailModal.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ const ShareEmailModal: React.FC<{ onClose: () => void }> = ({ onClose }) => {
153153
✓ Email sent successfully!
154154
</p>
155155
)}
156+
<div className="mt-3 p-2 bg-gray-50 rounded-md text-xs text-gray-600 border border-gray-200">
157+
<p>Only public statements will be shared. For details on how we process your data, see our <a href="#" className="text-brand-pink underline">Privacy Policy</a>.</p>
158+
</div>
156159
</div>
157160

158161
{sendError && (

src/components/modals/UserDataModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useEntries } from '../../features/statements/hooks/useEntries';
55
import { useAuth } from '../../features/auth/api/hooks';
66
import { Button } from '../ui/button';
77
import { Input } from '../ui/input';
8-
import { Save, X, User, Mail, Award, Edit2, LogOut } from 'lucide-react';
8+
import { Save, X, User, Mail, Award, Edit2, LogOut, Shield } from 'lucide-react';
99
import { Tooltip, TooltipTrigger, TooltipContent } from '../ui/better-tooltip';
1010
import { validateEmail } from '../../lib/utils/validateEmail';
1111
import QuestionCounter from '../ui/questionCounter/QuestionCounter';

src/features/auth/components/LoginPage.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@ const LoginPage: React.FC<LoginPageProps> = ({ onSubmit }) => {
124124
<p className='mb-6 text-center text-gray-700'>
125125
Sign in with your email to access the application.
126126
</p>
127+
<div className="mb-4 p-3 bg-gray-50 rounded-md border border-gray-200 text-sm text-gray-600">
128+
<p className="mb-2">
129+
By signing in, you agree to our <a href="#" className="text-brand-pink underline">Privacy Policy</a> and <a href="#" className="text-brand-pink underline">Terms of Use</a>.
130+
</p>
131+
<p>
132+
We collect and process your data to provide the Beacons service. You control what information is shared with your employer.
133+
</p>
134+
</div>
127135
<MagicLinkForm callbackURL="/main" />
128136
</>
129137
) : (

src/layouts/components/Header.tsx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ import React, { useState } from 'react';
33
import { useEntries } from '../../features/statements/hooks/useEntries';
44
import SmallCircularQuestionCounter from '../../components/ui/questionCounter/smallCircularQuestionCounter';
55
import UserDataModal from '../../components/modals/UserDataModal';
6+
import PrivacyModal from '../../components/modals/PrivacyModal';
7+
import { Shield } from 'lucide-react';
8+
import { Tooltip, TooltipTrigger, TooltipContent } from '../../components/ui/better-tooltip';
69

710
const Header: React.FC = () => {
811
const { data } = useEntries();
912
const [isDashboardOpen, setIsDashboardOpen] = useState(false);
13+
const [isPrivacyModalOpen, setIsPrivacyModalOpen] = useState(false);
1014

1115
// Debug output to make sure username is correct
1216
//console.log("Header rendering with username:", data.username);
@@ -16,15 +20,32 @@ const Header: React.FC = () => {
1620
console.log('Opening modal directly');
1721
setIsDashboardOpen(true);
1822
};
23+
24+
// Function to open the privacy modal
25+
const openPrivacyModal = () => {
26+
setIsPrivacyModalOpen(true);
27+
};
1928

2029
return (
2130
<header className='bg-brand-pink text-white p-4 shadow-md sticky top-0 z-50'>
2231
<div className='container mx-auto'>
2332
{/* Simplified header layout */}
2433
<div className='flex flex-wrap items-center justify-between'>
25-
{/* Left section: Logo */}
34+
{/* Left section: Logo and Privacy */}
2635
<div className='flex items-center'>
2736
<img src='/lift_logo.png' alt='Logo' className='h-8 sm:h-10 mr-2' />
37+
<Tooltip>
38+
<TooltipTrigger asChild>
39+
<button
40+
onClick={openPrivacyModal}
41+
className="ml-2 p-1 rounded-full hover:bg-pink-700 transition-colors"
42+
aria-label="Privacy Information"
43+
>
44+
<Shield size={16} />
45+
</button>
46+
</TooltipTrigger>
47+
<TooltipContent>Privacy Information</TooltipContent>
48+
</Tooltip>
2849
</div>
2950

3051
{/* Center section: Title */}
@@ -53,13 +74,18 @@ const Header: React.FC = () => {
5374
</div>
5475
)}
5576

56-
{/* Render the modal directly when open */}
77+
{/* Render the user data modal when open */}
5778
{isDashboardOpen && (
5879
<UserDataModal onOpenChange={setIsDashboardOpen} />
5980
)}
6081
</div>
6182
</div>
6283
</div>
84+
85+
{/* Render the privacy modal when open */}
86+
{isPrivacyModalOpen && (
87+
<PrivacyModal onClose={() => setIsPrivacyModalOpen(false)} />
88+
)}
6389
</header>
6490
);
6591
};

src/layouts/components/MainPage.tsx

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { Button } from '../../components/ui/button';
1212
import { Plus, Mail } from 'lucide-react';
1313
import StatementWizard from '../../features/wizard/components/StatementWizard';
1414
import ShareEmailModal from '../../components/modals/ShareEmailModal';
15-
import TestStatementButton from '../../components/debug/TestButton';
15+
// import TestStatementButton from '../../components/debug/TestButton';
1616

1717
const MainPage: React.FC = () => {
1818
const { data } = useEntries();
@@ -41,7 +41,7 @@ const MainPage: React.FC = () => {
4141
};
4242

4343
return (
44-
<main className='min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 py-12'>
44+
<main className='min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 py-12 flex flex-col'>
4545
<div className='container mx-auto px-4 mb-6'>
4646
{/* Fixed header layout with 1 or 2 rows */}
4747
<div className='flex flex-col md:flex-row md:justify-between md:items-center'>
@@ -50,7 +50,7 @@ const MainPage: React.FC = () => {
5050
? `${username} would like to share with ${managerName}`
5151
: `${username}'s statements for sharing`}
5252
</h1>
53-
53+
5454
<Button
5555
onClick={handleNewStatement}
5656
variant='pink'
@@ -61,12 +61,23 @@ const MainPage: React.FC = () => {
6161
</Button>
6262
</div>
6363
</div>
64-
65-
<div className='container mx-auto px-4'>
66-
64+
65+
<div className='container mx-auto px-4 flex-grow'>
6766
<StatementList username={username} />
6867
</div>
6968

69+
{/* Footer with privacy links */}
70+
<footer className="mt-auto pt-6 pb-4 bg-gray-50 border-t border-gray-200">
71+
<div className="container mx-auto px-4">
72+
<div className="flex flex-col sm:flex-row justify-center items-center text-xs text-gray-500 space-y-2 sm:space-y-0 sm:space-x-4">
73+
<a href="#" className="hover:text-brand-pink hover:underline">Privacy Policy</a>
74+
<a href="#" className="hover:text-brand-pink hover:underline">Terms of Use</a>
75+
<a href="#" className="hover:text-brand-pink hover:underline">Data Protection</a>
76+
<span>© {new Date().getFullYear()} Beacons</span>
77+
</div>
78+
</div>
79+
</footer>
80+
7081
{/* Floating Email Button (now singular) */}
7182
<div className='fixed bottom-8 right-8 z-30'>
7283
{/* Email Button: Disabled if there's no manager email or no public statements */}
@@ -95,11 +106,11 @@ const MainPage: React.FC = () => {
95106
: 'Send email with your public statements.'}
96107
</TooltipContent>
97108
</Tooltip>
98-
109+
99110
{/* Debug button */}
100-
<div className='mt-2'>
111+
{/* <div className='mt-2'>
101112
<TestStatementButton />
102-
</div>
113+
</div> */}
103114
</div>
104115

105116
{/* Conditionally render the wizard modal */}

0 commit comments

Comments
 (0)