Skip to content

Commit b422191

Browse files
committed
major refactor in app, new feilds and refreshed ui
1 parent 2b1f914 commit b422191

22 files changed

Lines changed: 3943 additions & 1318 deletions

app/dashboard/page.tsx

Lines changed: 192 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,27 @@ import { onAuthStateChanged, User, EmailAuthProvider, reauthenticateWithCredenti
88
import { doc, getDoc, getFirestore, deleteDoc } from 'firebase/firestore';
99
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
1010
import QRCode from 'qrcode';
11+
import { decryptData } from '@/lib/utils';
12+
import { Button } from '@/components/ui/button';
13+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
14+
import { Input } from '@/components/ui/input';
15+
import { Alert, AlertDescription } from '@/components/ui/alert';
16+
import { PageWrapper } from '@/components/ui/page-wrapper';
17+
import { PinInputDialog } from '@/components/ui/pin-input-dialog';
18+
import { DeleteAccountDialog } from '@/components/ui/delete-account-dialog';
19+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
1120

1221
const Dashboard = () => {
1322
const [user, setUser] = useState<User | null>(null);
1423
const [userName, setUserName] = useState<string>('');
1524
const [bloodGroup, setBloodGroup] = useState<string>('');
1625
const [tagID, setTagID] = useState<string | null>(null);
1726
const [loading, setLoading] = useState<boolean>(true);
27+
const [pinDialogOpen, setPinDialogOpen] = useState(false);
28+
const [pinError, setPinError] = useState<string | null>(null);
29+
const [verifyingPin, setVerifyingPin] = useState(false);
30+
const [rawData, setRawData] = useState<any>(null);
31+
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
1832
const router = useRouter();
1933

2034
useEffect(() => {
@@ -37,6 +51,7 @@ const Dashboard = () => {
3751

3852
if (userDoc.exists()) {
3953
const userData = userDoc.data();
54+
setRawData(userData);
4055
setUserName(userData.fullName);
4156
setBloodGroup(userData.bloodGroup);
4257
} else {
@@ -54,7 +69,51 @@ const Dashboard = () => {
5469
return () => unsubscribe();
5570
}, [router]);
5671

57-
const handlePrintTag = async () => {
72+
const handleInitiateTagDownload = () => {
73+
if (!tagID || !rawData) return;
74+
75+
// If data is encrypted, ask for PIN before generating the tag
76+
if (rawData.isEncrypted && rawData.encryptedData) {
77+
setPinDialogOpen(true);
78+
setPinError(null);
79+
} else {
80+
// Legacy unencrypted data, generate tag directly
81+
handlePrintTag(null);
82+
}
83+
};
84+
85+
const handleVerifyPin = async (pin: string) => {
86+
if (!pin || pin.length !== 4 || !/^\d{4}$/.test(pin)) {
87+
setPinError('Please enter a valid 4-digit PIN');
88+
return;
89+
}
90+
91+
setVerifyingPin(true);
92+
setPinError(null);
93+
94+
try {
95+
// Try to decrypt the data with the provided PIN
96+
const decryptedDataStr = await decryptData(rawData.encryptedData, pin);
97+
98+
try {
99+
// If we can parse the JSON, the PIN is correct
100+
JSON.parse(decryptedDataStr);
101+
102+
// PIN verified, proceed with tag generation
103+
handlePrintTag(pin);
104+
setPinDialogOpen(false);
105+
} catch (e) {
106+
setPinError('Incorrect PIN. Please try again.');
107+
}
108+
} catch (error) {
109+
console.error('Error verifying PIN:', error);
110+
setPinError('Incorrect PIN. Please try again.');
111+
} finally {
112+
setVerifyingPin(false);
113+
}
114+
};
115+
116+
const handlePrintTag = async (verifiedPin: string | null) => {
58117
if (!tagID) return;
59118

60119
const existingPdfBytes = await fetch('/template.pdf').then(res => res.arrayBuffer());
@@ -66,8 +125,8 @@ const Dashboard = () => {
66125
const qrCodeOptions = {
67126
margin: 0,
68127
color: {
69-
dark: '#FFFFFF', // Red color
70-
light: '#ff3131', // White background
128+
dark: '#FFFFFF', // Red color
129+
light: '#ff3131', // White background
71130
},
72131
};
73132

@@ -97,6 +156,17 @@ const Dashboard = () => {
97156
color: rgb(1, 1, 1),
98157
});
99158

159+
// Add PIN to the PDF tag if verified
160+
if (verifiedPin) {
161+
firstPage.drawText(`PIN: ${verifiedPin}`, {
162+
x: 150,
163+
y: 87,
164+
size: 14,
165+
font: await pdfDoc.embedFont(StandardFonts.HelveticaBold),
166+
color: rgb(1, 1, 1),
167+
});
168+
}
169+
100170
const pdfBytes = await pdfDoc.save();
101171
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
102172
const url = URL.createObjectURL(blob);
@@ -124,93 +194,132 @@ const Dashboard = () => {
124194
router.push('/login');
125195
} catch (error) {
126196
console.error('Error deleting account:', error);
197+
throw error; // Re-throw to be caught by the dialog
127198
}
128199
};
129200

130-
if (loading) {
131-
return (
132-
<div className="flex items-center justify-center min-h-screen">
133-
<div className="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-red-500"></div>
134-
</div>
135-
);
136-
}
137-
138201
return (
139-
<div className="min-h-screen bg-white dark:bg-black my-16 p-6">
140-
<div className="max-w-4xl mx-auto bg-stone-100 dark:bg-stone-800 rounded-lg p-6">
141-
<h1 className="text-2xl font-bold text-stone-800 dark:text-stone-200">
142-
Welcome, <span className="text-red-500">{userName || 'User'}</span>
143-
</h1>
144-
<p className="mt-2 text-stone-600 dark:text-stone-400">
145-
<strong>Tag ID:</strong> {tagID || 'N/A'}
146-
</p>
147-
148-
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-6">
149-
{tagID && (
150-
<>
151-
<button
152-
onClick={handlePrintTag}
153-
className="bg-black text-white py-2 px-4 rounded shadow hover:bg-stone-800 dark:hover:bg-stone-700 transition w-full"
154-
>
155-
Download / Print QR Tag <span className="text-sm text-[#bbbbbb]">PDF</span>
156-
</button>
157-
<Link href={`/id?id=${tagID}`} passHref>
158-
<button className="bg-black text-white py-2 px-4 rounded shadow hover:bg-stone-800 dark:hover:bg-stone-700 transition w-full">
159-
View Profile
160-
</button>
161-
</Link>
162-
</>
163-
)}
164-
<Link href="/update" passHref>
165-
<button className="bg-black text-white py-2 px-4 rounded shadow hover:bg-stone-800 dark:hover:bg-stone-700 transition w-full">
166-
Modify Data
167-
</button>
168-
</Link>
169-
<button
170-
onClick={() => {
171-
const password = prompt('Please enter your password to confirm account deletion:');
172-
if (password) {
173-
handleDeleteAccount(password);
174-
}
175-
}}
176-
className="bg-black text-white py-2 px-4 rounded shadow hover:bg-stone-800 dark:hover:bg-stone-700 transition w-full"
177-
>
178-
Delete Account
179-
</button>
180-
</div>
202+
<PageWrapper isLoading={loading}>
203+
<div className="max-w-4xl mx-auto">
204+
<Card className="mb-6">
205+
<CardHeader>
206+
<CardTitle className="flex flex-col sm:flex-row sm:items-center justify-between">
207+
<span>
208+
Welcome, <span className="text-red-500">{userName || 'User'}</span>
209+
</span>
210+
{tagID && (
211+
<span className="text-sm font-normal mt-2 sm:mt-0">
212+
Tag ID: <span className="font-mono">{tagID}</span>
213+
</span>
214+
)}
215+
</CardTitle>
216+
</CardHeader>
217+
<CardContent>
218+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
219+
{tagID && (
220+
<>
221+
<Button
222+
onClick={handleInitiateTagDownload}
223+
className="w-full"
224+
>
225+
Download / Print QR Tag
226+
</Button>
227+
<Button
228+
variant="outline"
229+
asChild
230+
className="w-full"
231+
>
232+
<Link href={`/id?id=${tagID}`}>View Profile</Link>
233+
</Button>
234+
</>
235+
)}
236+
<Button
237+
variant="outline"
238+
asChild
239+
className="w-full"
240+
>
241+
<Link href="/update">Modify Data</Link>
242+
</Button>
243+
<Button
244+
variant="destructive"
245+
onClick={() => setDeleteDialogOpen(true)}
246+
className="w-full"
247+
>
248+
Delete Account
249+
</Button>
250+
</div>
251+
</CardContent>
252+
</Card>
181253

182-
<div className="mt-10">
183-
<h2 className="text-xl font-semibold text-stone-800 dark:text-stone-200">Safety Tips & QR Code Usage</h2>
184-
<ul className="list-disc list-inside mt-4 text-stone-600 dark:text-stone-400">
185-
<li>Place your QR code tag on your helmet, vehicle, or ID card for easy access.</li>
186-
<li>Ensure the QR code is not obstructed by scratches or dirt for proper scanning.</li>
187-
<li>Share your tag ID with trusted contacts for emergencies.</li>
188-
<li>Do not share sensitive personal details through the QR code.</li>
189-
</ul>
190-
</div>
254+
<Card className="mb-6">
255+
<CardHeader>
256+
<CardTitle>Safety Tips & QR Code Usage</CardTitle>
257+
</CardHeader>
258+
<CardContent>
259+
<ul className="list-disc list-inside space-y-2">
260+
<li>Place your QR code tag on your helmet, vehicle, or ID card for easy access.</li>
261+
<li>Ensure the QR code is not obstructed by scratches or dirt for proper scanning.</li>
262+
<li>Share your tag ID with trusted contacts for emergencies.</li>
263+
<li>Do not share sensitive personal details through the QR code.</li>
264+
</ul>
265+
</CardContent>
266+
</Card>
191267

192-
<div className="mt-10">
193-
<h2 className="text-xl font-semibold text-stone-800 dark:text-stone-200">Where to Use OpenTag</h2>
194-
<ul className="list-disc list-inside mt-4 text-stone-600 dark:text-stone-400">
195-
<li>Stick the QR code tag on your backpack, helmet, car, or any personal item.</li>
196-
<li>Print six tags on a sheet, cut them out, and stick them using tape.</li>
197-
<li>Ensure the tags are placed in visible and easily accessible locations.</li>
198-
<li>Replace the tags if they get damaged or worn out.</li>
199-
</ul>
200-
</div>
201-
<div className="mt-10">
202-
<h2 className="text-xl font-semibold text-stone-800 dark:text-stone-200">Get Creative with Your QR Codes</h2>
203-
<p className="mt-4 text-stone-600 dark:text-stone-400">
204-
Feel free to customize your QR codes to match your style! You can use different colors, add logos, or even create unique designs. Just make sure the QR code remains scannable. Here are some tips:
205-
</p>
206-
<ul className="list-disc list-inside mt-4 text-stone-600 dark:text-stone-400">
207-
<li>Use high-contrast colors for the QR code and background.</li>
208-
<li>Experiment with different shapes and patterns, but keep the core structure intact.</li>
209-
<li>Test your custom QR codes with multiple devices to ensure they work properly.</li>
210-
</ul>
211-
</div>
268+
<Card className="mb-6">
269+
<CardHeader>
270+
<CardTitle>Where to Use OpenTag</CardTitle>
271+
</CardHeader>
272+
<CardContent>
273+
<ul className="list-disc list-inside space-y-2">
274+
<li>Stick the QR code tag on your backpack, helmet, car, or any personal item.</li>
275+
<li>Print six tags on a sheet, cut them out, and stick them using tape.</li>
276+
<li>Ensure the tags are placed in visible and easily accessible locations.</li>
277+
<li>Replace the tags if they get damaged or worn out.</li>
278+
</ul>
279+
</CardContent>
280+
</Card>
281+
282+
<Card>
283+
<CardHeader>
284+
<CardTitle>Get Creative with Your QR Codes</CardTitle>
285+
</CardHeader>
286+
<CardContent>
287+
<p className="mb-4">
288+
Feel free to customize your QR codes to match your style! You can use different colors, add logos, or even create unique designs. Just make sure the QR code remains scannable.
289+
</p>
290+
<ul className="list-disc list-inside space-y-2">
291+
<li>Use high-contrast colors for the QR code and background.</li>
292+
<li>Experiment with different shapes and patterns, but keep the core structure intact.</li>
293+
<li>Test your custom QR codes with multiple devices to ensure they work properly.</li>
294+
</ul>
295+
</CardContent>
296+
</Card>
212297
</div>
213-
</div>
298+
299+
{/* PIN Verification Dialog */}
300+
<PinInputDialog
301+
isOpen={pinDialogOpen}
302+
onClose={() => setPinDialogOpen(false)}
303+
onVerify={handleVerifyPin}
304+
title="Enter your PIN to download tag"
305+
description="Your medical data is protected with a PIN. Please enter your 4-digit PIN to include it in your tag."
306+
isVerifying={verifyingPin}
307+
error={pinError}
308+
basicInfo={
309+
<div className="space-y-2">
310+
<p><strong>Name:</strong> {userName}</p>
311+
<p><strong>Blood Group:</strong> {bloodGroup}</p>
312+
</div>
313+
}
314+
/>
315+
316+
{/* Delete Account Dialog */}
317+
<DeleteAccountDialog
318+
isOpen={deleteDialogOpen}
319+
onClose={() => setDeleteDialogOpen(false)}
320+
onConfirm={handleDeleteAccount}
321+
/>
322+
</PageWrapper>
214323
);
215324
};
216325

0 commit comments

Comments
 (0)