11"use client" ;
22import { useState , useEffect } from "react" ;
33import { Card , CardHeader } from "@/components/ui/card" ;
4- import { useRouter } from "next/navigation" ;
54import QRCode from "qrcode.react" ;
65import { useAuth } from "@/lib/auth-context" ;
76import { setAuthToken , setAuthId } from "@/lib/authUtils" ;
87import { isMobileDevice , getDeepLinkUrl } from "@/lib/utils/mobile-detection" ;
98
109export default function LoginPage ( ) {
11- const router = useRouter ( ) ;
1210 const { login } = useAuth ( ) ;
1311 const [ qrData , setQrData ] = useState < string | null > ( null ) ;
1412 const [ sessionId , setSessionId ] = useState < string | null > ( null ) ;
1513 const [ error , setError ] = useState < string | null > ( null ) ;
1614 const [ isLoading , setIsLoading ] = useState ( true ) ;
15+ const [ isMobile , setIsMobile ] = useState ( false ) ;
16+
17+ useEffect ( ( ) => {
18+ setIsMobile ( isMobileDevice ( ) ) ;
19+ } , [ ] ) ;
1720
1821 useEffect ( ( ) => {
1922 const fetchQRCode = async ( ) => {
2023 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+ ) ;
2728
2829 if ( ! response . ok ) {
2930 throw new Error ( "Failed to fetch QR code" ) ;
@@ -33,7 +34,7 @@ export default function LoginPage() {
3334 setQrData ( data . offer ) ;
3435 setSessionId ( data . sessionId ) ;
3536 setIsLoading ( false ) ;
36- } catch ( err ) {
37+ } catch {
3738 setError ( "Failed to load QR code" ) ;
3839 setIsLoading ( false ) ;
3940 }
@@ -54,59 +55,69 @@ export default function LoginPage() {
5455 if ( data . token && data . user ) {
5556 setAuthToken ( data . token ) ;
5657 setAuthId ( data . user . id ) ;
57- // Reload to trigger auth initialization
58- window . location . href = '/' ;
58+ window . location . href = "/" ;
5959 }
6060 } ;
6161
6262 eventSource . onerror = ( ) => {
6363 eventSource . close ( ) ;
6464 } ;
6565
66- return ( ) => {
67- eventSource . close ( ) ;
68- } ;
66+ return ( ) => eventSource . close ( ) ;
6967 } , [ sessionId , login ] ) ;
7068
7169 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 */ }
7372 < div className = "flex flex-col items-center text-center gap-4" >
7473 < div className = "flex items-center gap-2 text-2xl font-bold" >
7574 < img src = "/Logo.png" alt = "eVoting Logo" className = "h-12" />
7675 eVoting
7776 </ 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 >
7978 </ 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" >
8283 Welcome to eVoting
8384 </ 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+ ) }
89102 </ 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+
95106 { isLoading ? (
96107 < div className = "w-48 h-48 bg-gray-100 rounded-lg flex items-center justify-center" >
97108 < div className = "text-gray-500" > Loading QR Code...</ div >
98109 </ div >
99110 ) : qrData ? (
100111 < >
101- { isMobileDevice ( ) ? (
112+ { isMobile ? (
102113 < div className = "flex flex-col gap-4 items-center" >
103114 < a
104115 href = { getDeepLinkUrl ( qrData ) }
105116 className = "px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-center"
106117 >
107118 Login with eID Wallet
108119 </ 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" >
110121 Click the button to open your eID wallet app
111122 </ div >
112123 </ div >
@@ -126,21 +137,26 @@ export default function LoginPage() {
126137 < div className = "text-gray-500" > QR Code not available</ div >
127138 </ div >
128139 ) }
129- < span className = "flex flex-col gap-2 items-center" >
140+
141+ { /* Expiry Note */ }
142+ < div >
130143 < p className = "font-bold text-md" >
131144 The code is only valid for 60 seconds
132145 </ p >
133146 < 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
138153 is designed around the principle of data-platform
139154 separation, where all your personal content is stored in
140155 your own sovereign eVault, not on centralised servers.
141156 </ div >
142157 </ div >
143158 </ Card >
159+
144160 < img src = "/W3DS.svg" alt = "w3ds Logo" className = "max-h-8" />
145161 </ div >
146162 ) ;
0 commit comments