Skip to content

Commit 6c0c7fe

Browse files
committed
feat: eVoting responsiveness
1 parent 62e4aca commit 6c0c7fe

File tree

12 files changed

+206
-124
lines changed

12 files changed

+206
-124
lines changed

infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -787,12 +787,7 @@
787787
<h3 class="text-lg font-semibold text-gray-900 mb-2">
788788
Vote Signed Successfully!
789789
</h3>
790-
<p class="text-gray-600">
791-
Your vote has been signed and submitted to the eVoting system.
792-
</p>
793-
<p class="text-gray-500 text-sm mt-2">
794-
Redirecting you back to the platform...
795-
</p>
790+
<p class="text-gray-600">You can return to the platform</p>
796791

797792
{#if signingData?.redirect_uri}
798793
<div class="mt-4">

platforms/blabsy/AUTHENTICATION_SECURITY.md

Lines changed: 0 additions & 57 deletions
This file was deleted.

platforms/blabsy/src/components/login/login-main.tsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
44
import { useAuth } from '@lib/context/auth-context';
55
import { NextImage } from '@components/ui/next-image';
66
import Image from 'next/image';
7+
import { isMobileDevice, getDeepLinkUrl } from '@lib/utils/mobile-detection';
78

89
export function LoginMain(): JSX.Element {
910
const { signInWithCustomToken } = useAuth();
@@ -62,7 +63,7 @@ export function LoginMain(): JSX.Element {
6263
useSkeleton
6364
/>
6465
</div>
65-
<div className='flex flex-col items-center justify-between gap-6 p-8 lg:items-start lg:justify-center'>
66+
<div className='flex flex-col items-center justify-between gap-6 p-8 lg:items-start lg:justify-center min-h-screen'>
6667
<div className='flex max-w-xs flex-col gap-4 font-twitter-chirp-extended lg:max-w-none lg:gap-16'>
6768
<h1 className='text-3xl before:content-["See_what’s_happening_in_the_world_right_now."] lg:text-6xl lg:before:content-["Happening_now"]'>
6869
<span className='sr-only'>
@@ -73,9 +74,23 @@ export function LoginMain(): JSX.Element {
7374
Join Blabsy today.
7475
</h2>
7576
<div>
76-
<div className='p-2 rounded-md bg-white w-fit'>
77-
{qr && <QRCode value={qr} />}
78-
</div>
77+
{isMobileDevice() ? (
78+
<div className='flex flex-col gap-4 items-center'>
79+
<a
80+
href={qr ? getDeepLinkUrl(qr) : '#'}
81+
className='px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-center'
82+
>
83+
Login with eID Wallet
84+
</a>
85+
<div className='text-xs text-gray-500 text-center max-w-xs'>
86+
Click the button to open your eID wallet app
87+
</div>
88+
</div>
89+
) : (
90+
<div className='p-2 rounded-md bg-white w-fit'>
91+
{qr && <QRCode value={qr} />}
92+
</div>
93+
)}
7994
</div>
8095
<div className='absolute right-0 rotate-90 top-1/2'>
8196
<Image
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export function isMobileDevice(): boolean {
2+
if (typeof window === 'undefined') return false;
3+
4+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
5+
(window.innerWidth <= 768);
6+
}
7+
8+
export function getDeepLinkUrl(qrData: string): string {
9+
return qrData;
10+
}

platforms/eVoting/src/app/(app)/create/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export default function CreatePoll() {
163163
}
164164
className="mt-2"
165165
>
166-
<div className="grid grid-cols-3 gap-4">
166+
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
167167
<Label className="flex items-center cursor-pointer">
168168
<RadioGroupItem
169169
value="normal"
@@ -255,7 +255,7 @@ export default function CreatePoll() {
255255
disabled
256256
className="mt-2"
257257
>
258-
<div className="grid grid-cols-2 gap-4">
258+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
259259
<Label className="flex items-center cursor-not-allowed opacity-50">
260260
<RadioGroupItem
261261
value="1p1v"
@@ -318,7 +318,7 @@ export default function CreatePoll() {
318318
}
319319
className="mt-2"
320320
>
321-
<div className="grid grid-cols-2 gap-4">
321+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
322322
<Label className="flex items-center cursor-pointer">
323323
<RadioGroupItem
324324
value="public"

platforms/eVoting/src/app/(auth)/login/page.tsx

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useRouter } from "next/navigation";
55
import QRCode from "qrcode.react";
66
import { useAuth } from "@/lib/auth-context";
77
import { setAuthToken, setAuthId } from "@/lib/authUtils";
8+
import { isMobileDevice, getDeepLinkUrl } from "@/lib/utils/mobile-detection";
89

910
export default function LoginPage() {
1011
const router = useRouter();
@@ -51,11 +52,10 @@ export default function LoginPage() {
5152
eventSource.onmessage = (event) => {
5253
const data = JSON.parse(event.data);
5354
if (data.token && data.user) {
54-
// Store the token and user ID using auth utilities
5555
setAuthToken(data.token);
5656
setAuthId(data.user.id);
5757
// Reload to trigger auth initialization
58-
window.location.reload();
58+
window.location.href = '/';
5959
}
6060
};
6161

@@ -69,15 +69,15 @@ export default function LoginPage() {
6969
}, [sessionId, login]);
7070

7171
return (
72-
<div className="flex flex-col items-center justify-center gap-4 mt-4">
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">
7373
<div className="flex flex-col items-center text-center gap-4">
7474
<div className="flex items-center gap-2 text-2xl font-bold">
7575
<img src="/Logo.png" alt="eVoting Logo" className="h-12" />
7676
eVoting
7777
</div>
7878
<p className="text-2xl">Secure voting in the W3DS</p>
7979
</div>
80-
<Card className="flex flex-col items-center gap-1 w-1/3 p-4 pt-2">
80+
<Card className="flex flex-col items-center gap-1 w-full max-w-md p-4 pt-2 mx-4">
8181
<CardHeader className="text-foreground text-2xl font-black">
8282
Welcome to eVoting
8383
</CardHeader>
@@ -97,14 +97,30 @@ export default function LoginPage() {
9797
<div className="text-gray-500">Loading QR Code...</div>
9898
</div>
9999
) : qrData ? (
100-
<div className="p-4 bg-white rounded-lg">
101-
<QRCode
102-
value={qrData}
103-
size={200}
104-
level="M"
105-
includeMargin={true}
106-
/>
107-
</div>
100+
<>
101+
{isMobileDevice() ? (
102+
<div className="flex flex-col gap-4 items-center">
103+
<a
104+
href={getDeepLinkUrl(qrData)}
105+
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-center"
106+
>
107+
Login with eID Wallet
108+
</a>
109+
<div className="text-xs text-gray-500 text-center max-w-xs">
110+
Click the button to open your eID wallet app
111+
</div>
112+
</div>
113+
) : (
114+
<div className="p-4 bg-white rounded-lg">
115+
<QRCode
116+
value={qrData}
117+
size={200}
118+
level="M"
119+
includeMargin={true}
120+
/>
121+
</div>
122+
)}
123+
</>
108124
) : (
109125
<div className="w-48 h-48 bg-gray-100 rounded-lg flex items-center justify-center">
110126
<div className="text-gray-500">QR Code not available</div>

platforms/eVoting/src/app/globals.css

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,3 +336,57 @@ button[class*="bg-[--crimson]"]:hover {
336336
color: var(--crimson) !important;
337337
border-color: var(--crimson) !important;
338338
}
339+
340+
/* iOS Safari viewport height fix */
341+
@supports (-webkit-touch-callout: none) {
342+
.min-h-screen {
343+
min-height: -webkit-fill-available;
344+
}
345+
346+
html,
347+
body {
348+
height: -webkit-fill-available;
349+
}
350+
}
351+
352+
/* Ensure proper viewport handling on mobile */
353+
html {
354+
height: 100%;
355+
overflow-x: hidden;
356+
}
357+
358+
body {
359+
min-height: 100%;
360+
overflow-x: hidden;
361+
}
362+
363+
/* iOS safe area support */
364+
@supports (padding: max(0px)) {
365+
.safe-area-top {
366+
padding-top: max(1rem, env(safe-area-inset-top));
367+
}
368+
369+
.safe-area-bottom {
370+
padding-bottom: max(1rem, env(safe-area-inset-bottom));
371+
}
372+
373+
.pb-safe {
374+
padding-bottom: max(1rem, env(safe-area-inset-bottom));
375+
}
376+
}
377+
378+
/* iOS modal positioning fixes */
379+
@supports (-webkit-touch-callout: none) {
380+
.modal-container {
381+
position: fixed;
382+
top: 0;
383+
left: 0;
384+
right: 0;
385+
bottom: 0;
386+
display: flex;
387+
align-items: center;
388+
justify-content: center;
389+
padding: env(safe-area-inset-top) env(safe-area-inset-right)
390+
env(safe-area-inset-bottom) env(safe-area-inset-left);
391+
}
392+
}

platforms/eVoting/src/components/navigation.tsx

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -138,23 +138,9 @@ export default function Navigation() {
138138

139139
{/* Mobile Navigation Overlay */}
140140
{mobileMenuOpen && (
141-
<div className="md:hidden fixed inset-0 z-50">
142-
{/* Backdrop */}
143-
<div
144-
className="fixed inset-0 bg-black bg-opacity-50"
145-
onClick={() => setMobileMenuOpen(false)}
146-
onKeyDown={(e) => {
147-
if (e.key === "Enter" || e.key === " ") {
148-
setMobileMenuOpen(false);
149-
}
150-
}}
151-
tabIndex={0}
152-
role="button"
153-
aria-label="Close mobile menu backdrop"
154-
/>
155-
141+
<div className="md:hidden">
156142
{/* Menu Content */}
157-
<div className="fixed top-16 left-0 right-0 bg-white border-b shadow-lg">
143+
<div className="absolute top-16 left-0 right-0 bg-white border-b shadow-lg z-50">
158144
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
159145
{isAuthenticated ? (
160146
<>

platforms/eVoting/src/components/signing-interface.tsx

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { useToast } from "@/hooks/use-toast";
99
import { Clock, CheckCircle, XCircle, AlertTriangle } from "lucide-react";
1010
import { pollApi } from "@/lib/pollApi";
1111
import { useAuth } from "@/lib/auth-context";
12+
import { isMobileDevice, getDeepLinkUrl } from "@/lib/utils/mobile-detection";
1213

1314
interface SigningInterfaceProps {
1415
pollId: string | number;
@@ -254,19 +255,35 @@ export function SigningInterface({ pollId, voteData, onSigningComplete, onCancel
254255
</CardHeader>
255256
<CardContent className="text-center space-y-4">
256257
{qrData && (
257-
<div className="bg-white p-4 rounded-lg inline-block">
258-
<SVG
259-
text={qrData}
260-
options={{
261-
margin: 2,
262-
width: 200,
263-
color: {
264-
dark: "#000000",
265-
light: "#FFFFFF",
266-
},
267-
}}
268-
/>
269-
</div>
258+
<>
259+
{isMobileDevice() ? (
260+
<div className="flex flex-col gap-4 items-center">
261+
<a
262+
href={getDeepLinkUrl(qrData)}
263+
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-center"
264+
>
265+
Sign Vote with eID Wallet
266+
</a>
267+
<div className="text-xs text-gray-500 text-center max-w-xs">
268+
Click the button to open your eID wallet app and sign your vote
269+
</div>
270+
</div>
271+
) : (
272+
<div className="bg-white p-4 rounded-lg inline-block">
273+
<SVG
274+
text={qrData}
275+
options={{
276+
margin: 2,
277+
width: 200,
278+
color: {
279+
dark: "#000000",
280+
light: "#FFFFFF",
281+
},
282+
}}
283+
/>
284+
</div>
285+
)}
286+
</>
270287
)}
271288

272289
<div className="space-y-2">
@@ -283,10 +300,21 @@ export function SigningInterface({ pollId, voteData, onSigningComplete, onCancel
283300
</div>
284301

285302
<div className="text-xs text-gray-500 space-y-1">
286-
<p>1. Open your eID Wallet app</p>
287-
<p>2. Scan this QR code</p>
288-
<p>3. Review and sign the message</p>
289-
<p>4. Your vote will be submitted automatically</p>
303+
{isMobileDevice() ? (
304+
<>
305+
<p>1. Click the button above</p>
306+
<p>2. Your eID wallet app will open</p>
307+
<p>3. Review and sign the message</p>
308+
<p>4. Your vote will be submitted automatically</p>
309+
</>
310+
) : (
311+
<>
312+
<p>1. Open your eID Wallet app</p>
313+
<p>2. Scan this QR code</p>
314+
<p>3. Review and sign the message</p>
315+
<p>4. Your vote will be submitted automatically</p>
316+
</>
317+
)}
290318
</div>
291319

292320
<Button onClick={onCancel} variant="outline" className="w-full">

0 commit comments

Comments
 (0)