Skip to content

Commit 8b571ab

Browse files
authored
Feat/mobile responsiveness (#292)
* feat: pictique login mobile responsive * fix: pictique cta text * fix: evoting login
1 parent 0c52c22 commit 8b571ab

File tree

2 files changed

+112
-69
lines changed

2 files changed

+112
-69
lines changed

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

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
"use client";
22
import { useState, useEffect } from "react";
33
import { Card, CardHeader } from "@/components/ui/card";
4-
import { useRouter } from "next/navigation";
54
import QRCode from "qrcode.react";
65
import { useAuth } from "@/lib/auth-context";
76
import { setAuthToken, setAuthId } from "@/lib/authUtils";
87
import { isMobileDevice, getDeepLinkUrl } from "@/lib/utils/mobile-detection";
98

109
export 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
);

platforms/pictique/src/routes/(auth)/auth/+page.svelte

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,20 @@
55
import { Qr } from '$lib/ui';
66
import { apiClient, setAuthId, setAuthToken } from '$lib/utils';
77
import { onMount } from 'svelte';
8+
import { onDestroy } from 'svelte';
89
import { qrcode } from 'svelte-qrcode-action';
910
1011
let qrData: string;
12+
let isMobile = false;
13+
14+
function checkMobile() {
15+
isMobile = window.innerWidth <= 640; // Tailwind's `sm` breakpoint
16+
}
1117
1218
onMount(async () => {
19+
checkMobile();
20+
window.addEventListener('resize', checkMobile);
21+
1322
const { data } = await apiClient.get('/api/auth/offer');
1423
qrData = data.uri;
1524
@@ -32,60 +41,78 @@
3241
}
3342
3443
watchEventStream(new URL(qrData).searchParams.get('session') as string);
44+
45+
onDestroy(() => {
46+
window.removeEventListener('resize', checkMobile);
47+
});
3548
});
3649
</script>
3750

38-
<div
39-
class="align-center flex h-full w-full flex-col content-center items-center
40-
justify-center"
41-
>
42-
<div class="mb-5 flex flex-col items-center gap-2">
51+
<div class="flex h-full w-full flex-col items-center justify-center p-4">
52+
<div class="mb-5 flex flex-col items-center gap-2 text-center">
4353
<img src="/images/Logo.svg" alt="logo" class="w-30" />
4454
<p>Connect Socially in the Metastate</p>
4555
</div>
56+
4657
<div
47-
class="h-max-[600px] w-max-[400px] mb-5 flex flex-col items-center gap-5 rounded-xl bg-[#F476481A] p-5"
58+
class="mb-5 flex w-full max-w-[400px] flex-col items-center gap-5 rounded-xl bg-[#F476481A] p-5"
4859
>
49-
<h2>Scan the QR code using your <b><u>eID App</u></b> to login</h2>
5060
{#if qrData}
51-
<article
52-
class="overflow-hidden rounded-2xl"
53-
use:qrcode={{
54-
data: qrData,
55-
width: 250,
56-
height: 250,
57-
margin: 12,
58-
type: 'canvas',
59-
dotsOptions: {
60-
type: 'rounded',
61-
color: '#fff'
62-
},
63-
backgroundOptions: {
64-
gradient: {
65-
type: 'linear',
66-
rotation: 50,
67-
colorStops: [
68-
{ offset: 0, color: '#4D44EF' },
69-
{ offset: 0.65, color: '#F35B5B' },
70-
{ offset: 1, color: '#F7A428' }
71-
]
61+
{#if isMobile}
62+
<h2 class="text-center">
63+
Click the button below to login using your <b><u>eID App</u></b>
64+
</h2>
65+
<a
66+
href={qrData}
67+
class="w-full rounded-lg bg-[#4D44EF] px-4 py-3 text-center font-semibold text-white transition hover:opacity-90"
68+
>
69+
Login with eID Wallet
70+
</a>
71+
{:else}
72+
<h2 class="text-center">
73+
Scan the QR code using your <b><u>eID App</u></b> to login
74+
</h2>
75+
<article
76+
class="overflow-hidden rounded-2xl"
77+
use:qrcode={{
78+
data: qrData,
79+
width: 250,
80+
height: 250,
81+
margin: 12,
82+
type: 'canvas',
83+
dotsOptions: {
84+
type: 'rounded',
85+
color: '#fff'
86+
},
87+
backgroundOptions: {
88+
gradient: {
89+
type: 'linear',
90+
rotation: 50,
91+
colorStops: [
92+
{ offset: 0, color: '#4D44EF' },
93+
{ offset: 0.65, color: '#F35B5B' },
94+
{ offset: 1, color: '#F7A428' }
95+
]
96+
}
7297
}
73-
}
74-
}}
75-
></article>
76-
<a href={qrData}>{qrData}</a>
98+
}}
99+
></article>
100+
{/if}
77101
{/if}
78-
<p>
102+
103+
<p class="text-center">
79104
<span class="mb-1 block font-bold text-gray-600">The code is valid for 60 seconds</span>
80105
<span class="block font-light text-gray-600">Please refresh the page if it expires</span
81106
>
82107
</p>
83-
<p class="w-[350px] bg-white/60 p-4 leading-4 text-black/60">
108+
109+
<p class="w-full rounded-md bg-white/60 p-4 text-sm leading-4 text-black/60">
84110
You are entering Pictique - a social network built on the Web 3.0 Data Space (W3DS)
85111
architecture. This system is designed around the principle of data-platform separation,
86112
where all your personal content is stored in your own sovereign eVault, not on
87113
centralised servers.
88114
</p>
89115
</div>
116+
90117
<W3dslogo />
91118
</div>

0 commit comments

Comments
 (0)