Skip to content

Commit f3965a4

Browse files
committed
added scanner to the home screen
1 parent 2e4cf16 commit f3965a4

2 files changed

Lines changed: 245 additions & 59 deletions

File tree

frontend/src/app/page.tsx

Lines changed: 8 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,12 @@
1-
"use client";
2-
3-
import { useState } from 'react';
4-
import MakerTab from '@/components/MakerTab';
5-
import ResolverTab from '@/components/ResolverTab';
6-
import AdminTab from '@/components/AdminTab';
7-
import ResolverApproval from '@/components/ResolverApproval';
8-
import { NetworkValidation } from '@/components/NetworkValidation';
9-
10-
export default function Home() {
11-
const [activeTab, setActiveTab] = useState('maker');
12-
13-
const tabs = [
14-
{ id: 'maker', label: 'Maker', component: <MakerTab /> },
15-
{ id: 'resolver', label: 'Resolver', component: <ResolverTab /> },
16-
{ id: 'admin', label: 'Admin', component: <AdminTab /> },
17-
];
1+
import React from 'react';
2+
import UpiQrScanner from '../components/UPIQRScanner';
183

4+
function App() {
195
return (
20-
<NetworkValidation>
21-
<div className="container mx-auto px-4 py-6">
22-
{/* Header */}
23-
<div className="text-center mb-8">
24-
<h1 className="text-3xl font-bold text-gray-800 mb-2">
25-
Order Protocol Dashboard
26-
</h1>
27-
<p className="text-gray-600">
28-
Manage makers, resolvers, and protocol administration
29-
</p>
30-
</div>
31-
32-
{/* Resolver Approval Section */}
33-
<div className="mb-8">
34-
<ResolverApproval />
35-
</div>
36-
37-
{/* Tab Navigation */}
38-
<div className="flex justify-center mb-8">
39-
<div className="bg-white rounded-lg shadow-md p-1 inline-flex">
40-
{tabs.map((tab) => (
41-
<button
42-
key={tab.id}
43-
onClick={() => setActiveTab(tab.id)}
44-
className={`px-6 py-3 rounded-md font-medium transition-all ${
45-
activeTab === tab.id
46-
? 'bg-blue-500 text-white shadow-md'
47-
: 'text-gray-600 hover:text-gray-800 hover:bg-gray-100'
48-
}`}
49-
>
50-
{tab.label}
51-
</button>
52-
))}
53-
</div>
54-
</div>
55-
56-
{/* Tab Content */}
57-
<div className="bg-white rounded-lg shadow-lg p-6">
58-
{tabs.find(tab => tab.id === activeTab)?.component}
59-
</div>
60-
</div>
61-
</NetworkValidation>
6+
<div className="App">
7+
<UpiQrScanner />
8+
</div>
629
);
6310
}
11+
12+
export default App;
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
"use client"
2+
import React, { useState, useEffect } from 'react';
3+
import { Scanner } from '@yudiel/react-qr-scanner';
4+
import { useAccount } from 'wagmi';
5+
import toast, { Toaster } from 'react-hot-toast';
6+
import { useRouter } from 'next/navigation';
7+
8+
const UpiQrScanner = () => {
9+
const { isConnected } = useAccount();
10+
const router = useRouter();
11+
const [scanResult, setScanResult] = useState<string | null>(null);
12+
const [jsonObject, setJsonObject] = useState<any>(null);
13+
const [error, setError] = useState<string | null>(null);
14+
const [isScanning, setIsScanning] = useState(false);
15+
16+
// Check wallet connection before starting scanner
17+
useEffect(() => {
18+
if (isConnected) {
19+
setIsScanning(true);
20+
} else {
21+
setIsScanning(false);
22+
toast.error('Please connect your wallet first to use QR scanner', {
23+
duration: 4000,
24+
position: 'bottom-right',
25+
style: {
26+
background: '#dc3545',
27+
color: 'white',
28+
fontWeight: 'bold',
29+
},
30+
});
31+
}
32+
}, [isConnected]);
33+
34+
const handleScan = (result: any) => {
35+
if (result && result.length > 0) {
36+
const scannedText = result[0]?.rawValue || result[0]?.data || result;
37+
38+
try {
39+
// Parse the UPI URL string into a JSON object
40+
const url = new URL(scannedText);
41+
const params = Object.fromEntries(url.searchParams.entries());
42+
43+
// Show success toast and immediately redirect
44+
toast.success('UPI QR Code scanned! Redirecting to create order...', {
45+
duration: 1500,
46+
position: 'bottom-right',
47+
style: {
48+
background: '#28a745',
49+
color: 'white',
50+
fontWeight: 'bold',
51+
},
52+
});
53+
54+
// Immediate redirect to maker dashboard with UPI data - no intermediate state
55+
const queryParams = new URLSearchParams({
56+
upiAddress: params.pa || '',
57+
payeeName: params.pn || '',
58+
amount: params.am || '',
59+
transactionRef: params.tr || '',
60+
merchantCode: params.mc || ''
61+
}).toString();
62+
63+
// Redirect immediately without setting any intermediate state
64+
router.push(`/maker-dashboard?tab=create&${queryParams}`);
65+
66+
} catch (err) {
67+
// If it's not a URL, try to parse as UPI format
68+
if (scannedText.toLowerCase().startsWith('upi://')) {
69+
try {
70+
const upiUrl = new URL(scannedText);
71+
const params = Object.fromEntries(upiUrl.searchParams.entries());
72+
73+
// Show success toast and immediately redirect
74+
toast.success('UPI QR Code scanned! Redirecting to create order...', {
75+
duration: 1500,
76+
position: 'bottom-right',
77+
style: {
78+
background: '#28a745',
79+
color: 'white',
80+
fontWeight: 'bold',
81+
},
82+
});
83+
84+
// Immediate redirect to maker dashboard with UPI data
85+
const queryParams = new URLSearchParams({
86+
upiAddress: params.pa || '',
87+
payeeName: params.pn || '',
88+
amount: params.am || '',
89+
transactionRef: params.tr || '',
90+
merchantCode: params.mc || ''
91+
}).toString();
92+
93+
// Redirect immediately without setting any intermediate state
94+
router.push(`/maker-dashboard?tab=create&${queryParams}`);
95+
96+
} catch (upiErr) {
97+
setError('Invalid UPI QR code format');
98+
setJsonObject(null);
99+
toast.error('Invalid UPI QR code format', {
100+
duration: 3000,
101+
position: 'bottom-right',
102+
style: {
103+
background: '#dc3545',
104+
color: 'white',
105+
fontWeight: 'bold',
106+
},
107+
});
108+
}
109+
} else {
110+
// For non-UPI QR codes, just show the raw data
111+
setJsonObject({ rawData: scannedText });
112+
setError(null);
113+
setIsScanning(false);
114+
}
115+
}
116+
}
117+
};
118+
119+
const handleError = (err: any) => {
120+
console.error('QR Scanner Error:', err);
121+
setError('Error scanning QR code: ' + (err?.message || 'Unknown error'));
122+
};
123+
124+
return (
125+
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 p-4">
126+
<Toaster
127+
position="bottom-right"
128+
toastOptions={{
129+
duration: 3000,
130+
style: {
131+
borderRadius: '12px',
132+
fontSize: '14px',
133+
fontWeight: '500',
134+
maxWidth: '90vw',
135+
},
136+
}}
137+
/>
138+
139+
<div className="max-w-md mx-auto">
140+
{/* Header */}
141+
<div className="text-center mb-8 pt-4">
142+
<div className="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-r from-blue-500 to-indigo-600 rounded-full mb-4 shadow-lg">
143+
<span className="text-2xl">📱</span>
144+
</div>
145+
<h1 className="text-3xl font-bold text-gray-800 mb-2">
146+
UPI QR Scanner
147+
</h1>
148+
<p className="text-gray-600 text-sm">
149+
Scan UPI QR codes to process payments
150+
</p>
151+
</div>
152+
153+
{/* Wallet Connection Status */}
154+
{!isConnected && (
155+
<div className="bg-blue-50 border-4 border-blue-300 rounded-xl p-6 mb-6 shadow-sm">
156+
<div className="flex items-center justify-center mb-4">
157+
<div className="w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center">
158+
<span className="text-2xl">🔒</span>
159+
</div>
160+
</div>
161+
<h3 className="text-lg font-semibold text-blue-800 text-center mb-2">
162+
Wallet Not Connected
163+
</h3>
164+
<p className="text-blue-600 text-center text-sm leading-relaxed">
165+
Connect your wallet to start scanning UPI QR codes and process payments securely
166+
</p>
167+
</div>
168+
)}
169+
170+
{/* Camera Scanner */}
171+
{isConnected && isScanning && !scanResult && (
172+
<div className="bg-white rounded-2xl shadow-lg overflow-hidden mb-6">
173+
{/* Scanner Header */}
174+
<div className="bg-gradient-to-r from-blue-500 to-indigo-600 px-6 py-4">
175+
<div className="flex items-center justify-center space-x-2">
176+
<span className="text-white font-medium">Scanning Active</span>
177+
</div>
178+
</div>
179+
180+
{/* Instructions */}
181+
<div className="px-6 py-4 bg-blue-50 border-b">
182+
<p className="text-center text-blue-700 font-medium text-sm">
183+
Point your camera at a UPI QR code
184+
</p>
185+
</div>
186+
187+
{/* Scanner Area */}
188+
<div className="p-4">
189+
<div className="relative rounded-xl overflow-hidden bg-black">
190+
<Scanner
191+
onScan={handleScan}
192+
onError={handleError}
193+
constraints={{
194+
facingMode: 'environment'
195+
}}
196+
styles={{
197+
container: {
198+
width: '100%',
199+
height: '280px',
200+
}
201+
}}
202+
allowMultiple={false}
203+
scanDelay={300}
204+
/>
205+
</div>
206+
207+
{/* Tips */}
208+
<div className="mt-4 text-center">
209+
<p className="text-xs text-gray-500 mb-2">💡 Tips for better scanning:</p>
210+
<div className="flex justify-center space-x-4 text-xs text-gray-400">
211+
<span>• Good lighting</span>
212+
<span>• Steady hands</span>
213+
<span>• Clear QR code</span>
214+
</div>
215+
</div>
216+
</div>
217+
</div>
218+
)}
219+
220+
{/* Error Display */}
221+
{error && (
222+
<div className="bg-red-50 border border-red-200 rounded-xl p-6 mb-6 shadow-sm">
223+
<div className="flex items-center justify-center mb-2">
224+
<span className="text-2xl mr-2"></span>
225+
<span className="text-red-800 font-semibold">Scan Error</span>
226+
</div>
227+
<p className="text-red-600 text-center text-sm">
228+
{error}
229+
</p>
230+
</div>
231+
)}
232+
</div>
233+
</div>
234+
);
235+
};
236+
237+
export default UpiQrScanner;

0 commit comments

Comments
 (0)