1
1
"use client" ;
2
2
import { useState , useEffect } from "react" ;
3
3
import { Card , CardHeader } from "@/components/ui/card" ;
4
- import { useRouter } from "next/navigation" ;
5
4
import QRCode from "qrcode.react" ;
6
5
import { useAuth } from "@/lib/auth-context" ;
7
6
import { setAuthToken , setAuthId } from "@/lib/authUtils" ;
8
7
import { isMobileDevice , getDeepLinkUrl } from "@/lib/utils/mobile-detection" ;
9
8
10
9
export default function LoginPage ( ) {
11
- const router = useRouter ( ) ;
12
10
const { login } = useAuth ( ) ;
13
11
const [ qrData , setQrData ] = useState < string | null > ( null ) ;
14
12
const [ sessionId , setSessionId ] = useState < string | null > ( null ) ;
15
13
const [ error , setError ] = useState < string | null > ( null ) ;
16
14
const [ isLoading , setIsLoading ] = useState ( true ) ;
15
+ const [ isMobile , setIsMobile ] = useState ( false ) ;
16
+
17
+ useEffect ( ( ) => {
18
+ setIsMobile ( isMobileDevice ( ) ) ;
19
+ } , [ ] ) ;
17
20
18
21
useEffect ( ( ) => {
19
22
const fetchQRCode = async ( ) => {
20
23
try {
21
- const response = await fetch ( `${ process . env . NEXT_PUBLIC_EVOTING_BASE_URL } /api/auth/offer` , {
22
- method : "GET" ,
23
- headers : {
24
- "Content-Type" : "application/json" ,
25
- } ,
26
- } ) ;
24
+ const response = await fetch (
25
+ `${ process . env . NEXT_PUBLIC_EVOTING_BASE_URL } /api/auth/offer` ,
26
+ { method : "GET" , headers : { "Content-Type" : "application/json" } }
27
+ ) ;
27
28
28
29
if ( ! response . ok ) {
29
30
throw new Error ( "Failed to fetch QR code" ) ;
@@ -33,7 +34,7 @@ export default function LoginPage() {
33
34
setQrData ( data . offer ) ;
34
35
setSessionId ( data . sessionId ) ;
35
36
setIsLoading ( false ) ;
36
- } catch ( err ) {
37
+ } catch {
37
38
setError ( "Failed to load QR code" ) ;
38
39
setIsLoading ( false ) ;
39
40
}
@@ -54,59 +55,69 @@ export default function LoginPage() {
54
55
if ( data . token && data . user ) {
55
56
setAuthToken ( data . token ) ;
56
57
setAuthId ( data . user . id ) ;
57
- // Reload to trigger auth initialization
58
- window . location . href = '/' ;
58
+ window . location . href = "/" ;
59
59
}
60
60
} ;
61
61
62
62
eventSource . onerror = ( ) => {
63
63
eventSource . close ( ) ;
64
64
} ;
65
65
66
- return ( ) => {
67
- eventSource . close ( ) ;
68
- } ;
66
+ return ( ) => eventSource . close ( ) ;
69
67
} , [ sessionId , login ] ) ;
70
68
71
69
return (
72
- < div className = "modal-container flex flex-col items-center justify-center gap-4 safe-area-top safe-area-bottom min-h-screen px-4 pb-safe" >
70
+ < div className = "flex flex-col items-center justify-center gap-4 min-h-screen px-4 pb-safe" >
71
+ { /* Logo + Tagline */ }
73
72
< div className = "flex flex-col items-center text-center gap-4" >
74
73
< div className = "flex items-center gap-2 text-2xl font-bold" >
75
74
< img src = "/Logo.png" alt = "eVoting Logo" className = "h-12" />
76
75
eVoting
77
76
</ div >
78
- < p className = "text-2xl" > Secure voting in the W3DS</ p >
77
+ < p className = "text-lg sm:text- 2xl" > Secure voting in the W3DS</ p >
79
78
</ div >
80
- < Card className = "flex flex-col items-center gap-1 w-full max-w-md p-4 pt-2 mx-4" >
81
- < CardHeader className = "text-foreground text-2xl font-black" >
79
+
80
+ { /* Main Card */ }
81
+ < Card className = "flex flex-col items-center gap-4 w-full max-w-md p-4 pt-2 mx-4" >
82
+ < CardHeader className = "text-foreground text-xl sm:text-2xl font-black text-center" >
82
83
Welcome to eVoting
83
84
</ CardHeader >
84
- < div className = "flex flex-col gap-4 text-muted-foreground items-center" >
85
- < div className = "flex justify-center items-center text-xl space-x-1 whitespace-nowrap" >
86
- < span > Scan the QR using your</ span >
87
- < span className = "font-bold underline" > eID App</ span >
88
- < span > to login</ span >
85
+
86
+ < div className = "flex flex-col gap-4 text-muted-foreground items-center text-center" >
87
+ { /* Dynamic heading text */ }
88
+ < div className = "text-lg sm:text-xl space-x-1" >
89
+ { isMobile ? (
90
+ < >
91
+ < span > Click the button below using your</ span >
92
+ < span className = "font-bold underline" > eID App</ span >
93
+ < span > to login</ span >
94
+ </ >
95
+ ) : (
96
+ < >
97
+ < span > Scan the QR using your</ span >
98
+ < span className = "font-bold underline" > eID App</ span >
99
+ < span > to login</ span >
100
+ </ >
101
+ ) }
89
102
</ div >
90
- { error && (
91
- < div className = "w-full text-red-500 text-center" >
92
- { error }
93
- </ div >
94
- ) }
103
+
104
+ { error && < div className = "w-full text-red-500" > { error } </ div > }
105
+
95
106
{ isLoading ? (
96
107
< div className = "w-48 h-48 bg-gray-100 rounded-lg flex items-center justify-center" >
97
108
< div className = "text-gray-500" > Loading QR Code...</ div >
98
109
</ div >
99
110
) : qrData ? (
100
111
< >
101
- { isMobileDevice ( ) ? (
112
+ { isMobile ? (
102
113
< div className = "flex flex-col gap-4 items-center" >
103
114
< a
104
115
href = { getDeepLinkUrl ( qrData ) }
105
116
className = "px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-center"
106
117
>
107
118
Login with eID Wallet
108
119
</ a >
109
- < div className = "text-xs text-gray-500 text-center max-w-xs" >
120
+ < div className = "text-xs text-gray-500 max-w-xs" >
110
121
Click the button to open your eID wallet app
111
122
</ div >
112
123
</ div >
@@ -126,21 +137,26 @@ export default function LoginPage() {
126
137
< div className = "text-gray-500" > QR Code not available</ div >
127
138
</ div >
128
139
) }
129
- < span className = "flex flex-col gap-2 items-center" >
140
+
141
+ { /* Expiry Note */ }
142
+ < div >
130
143
< p className = "font-bold text-md" >
131
144
The code is only valid for 60 seconds
132
145
</ p >
133
146
< p > Please refresh the page if it expires</ p >
134
- </ span >
135
- < div className = "bg-muted-foreground/20 p-4 rounded-md text-center" >
136
- You are entering eVoting - a voting platform built on
137
- the Web 3.0 Data Space (WDS) architecture. This system
147
+ </ div >
148
+
149
+ { /* Info Box */ }
150
+ < div className = "bg-muted-foreground/20 p-4 rounded-md" >
151
+ You are entering eVoting — a voting platform built on
152
+ the Web 3.0 Data Space (W3DS) architecture. This system
138
153
is designed around the principle of data-platform
139
154
separation, where all your personal content is stored in
140
155
your own sovereign eVault, not on centralised servers.
141
156
</ div >
142
157
</ div >
143
158
</ Card >
159
+
144
160
< img src = "/W3DS.svg" alt = "w3ds Logo" className = "max-h-8" />
145
161
</ div >
146
162
) ;
0 commit comments