From 9e403dc2c7e602dd0cbf500ca7838d048c86a796 Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 00:22:05 +0530 Subject: [PATCH 01/21] fix: ui/ux imrovements --- .../IdentityCard/IdentityCard.svelte | 50 ++++------ .../src/lib/ui/Drawer/Drawer.svelte | 18 ++-- .../eid-wallet/src/lib/ui/Toast/Toast.svelte | 86 +++++++++++++++++ .../eid-wallet/src/lib/ui/Toast/toast.ts | 53 +++++++++++ .../src/routes/(app)/main/+page.svelte | 34 ------- .../src/routes/(app)/scan-qr/+page.svelte | 28 ++---- .../src/routes/(app)/settings/+page.svelte | 3 +- .../src/routes/(auth)/onboarding/+page.svelte | 34 ++++++- .../src/routes/(auth)/verify/+page.svelte | 14 ++- .../(auth)/verify/steps/document-type.svelte | 29 +++++- .../(auth)/verify/steps/passport.svelte | 17 +++- .../routes/(auth)/verify/steps/selfie.svelte | 23 +++-- .../eid-wallet/src/routes/+layout.svelte | 92 ++++++++++++++++++- .../eid-wallet/src/routes/+page.svelte | 70 +++++++------- 14 files changed, 398 insertions(+), 153 deletions(-) create mode 100644 infrastructure/eid-wallet/src/lib/ui/Toast/Toast.svelte create mode 100644 infrastructure/eid-wallet/src/lib/ui/Toast/toast.ts diff --git a/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte b/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte index d91eacf39..69f9ceb5a 100644 --- a/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte +++ b/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte @@ -1,10 +1,10 @@ + +
+ {#each toasts as toast (toast.id)} + + {/each} +
+ + + diff --git a/infrastructure/eid-wallet/src/lib/ui/Toast/toast.ts b/infrastructure/eid-wallet/src/lib/ui/Toast/toast.ts new file mode 100644 index 000000000..05c693494 --- /dev/null +++ b/infrastructure/eid-wallet/src/lib/ui/Toast/toast.ts @@ -0,0 +1,53 @@ +import { writable } from "svelte/store"; + +export interface Toast { + id: string; + message: string; + type?: "success" | "error" | "info"; + duration?: number; +} + +const createToastStore = () => { + const { subscribe, update } = writable([]); + + return { + subscribe, + add: (toast: Omit) => { + const id = crypto.randomUUID(); + const newToast: Toast = { + id, + duration: 3000, + ...toast, + }; + + update((toasts) => [...toasts, newToast]); + + // Auto remove after duration + if (newToast.duration && newToast.duration > 0) { + setTimeout(() => { + remove(id); + }, newToast.duration); + } + + return id; + }, + remove: (id: string) => { + update((toasts) => toasts.filter((t) => t.id !== id)); + }, + clear: () => { + update(() => []); + }, + }; +}; + +export const toastStore = createToastStore(); + +export const toast = { + success: (message: string, duration?: number) => + toastStore.add({ message, type: "success", duration }), + error: (message: string, duration?: number) => + toastStore.add({ message, type: "error", duration }), + info: (message: string, duration?: number) => + toastStore.add({ message, type: "info", duration }), +}; + diff --git a/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte index b7706c0b5..2637e5513 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte @@ -2,10 +2,8 @@ import { goto } from "$app/navigation"; import { Hero, IdentityCard } from "$lib/fragments"; import type { GlobalState } from "$lib/global"; -import { Drawer } from "$lib/ui"; import * as Button from "$lib/ui/Button"; import { - CircleArrowDataTransferDiagonalFreeIcons, QrCodeIcon, Settings02Icon, } from "@hugeicons/core-free-icons"; @@ -13,7 +11,6 @@ import { HugeiconsIcon } from "@hugeicons/svelte"; import { type Snippet, getContext, onMount } from "svelte"; import { onDestroy } from "svelte"; import { Shadow } from "svelte-loading-spinners"; -import QrCode from "svelte-qrcode"; let userData: Record | undefined = $state(undefined); let greeting: string | undefined = $state(undefined); @@ -21,15 +18,9 @@ let ename: string | undefined = $state(undefined); let profileCreationStatus: "idle" | "loading" | "success" | "failed" = $state("idle"); -let shareQRdrawerOpen = $state(false); let statusInterval: ReturnType | undefined = $state(undefined); -function shareQR() { - alert("QR Code shared!"); - shareQRdrawerOpen = false; -} - async function retryProfileCreation() { try { await globalState.vaultController.retryProfileCreation(); @@ -137,14 +128,11 @@ onDestroy(() => { alert("View button clicked!")} - shareBtn={() => (shareQRdrawerOpen = true)} /> {/snippet} {#snippet ePassport()} goto("/ePassport")} userData={userData as Record} /> {/snippet} @@ -158,28 +146,6 @@ onDestroy(() => { {@render Section("eVault", eVault)} - -
- -
- -

Share your eName

-

- Anyone scanning this can see your eName -

-
- - Share - -
-
- { }); async function handleAuthDrawerDecline() { - // If there's an error, "Okay" button closes modal and navigates to main - if ($authError) { - setCodeScannedDrawerOpen(false); - await goto("/main"); - } else { - // Otherwise, "Decline" closes modal and restarts scanning - setCodeScannedDrawerOpen(false); - startScan(); - } + // Cancel button always navigates to main dashboard + setCodeScannedDrawerOpen(false); + await goto("/main"); } function handleAuthDrawerOpenChange(value: boolean) { @@ -126,15 +120,9 @@ function handleLoggedInDrawerOpenChange(value: boolean) { } async function handleSigningDrawerDecline() { - // If there's an error, "Okay" button closes modal and navigates to main - if ($signingError) { - setSigningDrawerOpen(false); - await goto("/main"); - } else { - // Otherwise, "Decline" closes modal and restarts scanning - setSigningDrawerOpen(false); - startScan(); - } + // Cancel button always navigates to main dashboard + setSigningDrawerOpen(false); + await goto("/main"); } function handleSigningDrawerOpenChange(value: boolean) { @@ -148,9 +136,9 @@ function handleBlindVoteOptionChange(index: number) { handleBlindVoteSelection(index); } -function handleRevealDrawerCancel() { +async function handleRevealDrawerCancel() { setRevealRequestOpen(false); - window.history.back(); + await goto("/main"); } function handleRevealDrawerOpenChange(value: boolean) { diff --git a/infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte index 16811b1a9..c485056c0 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte @@ -45,9 +45,10 @@ async function nukeWallet() { goto("/onboarding"); } -function cancelDelete() { +async function cancelDelete() { isDeleteConfirmationOpen = false; isFinalConfirmationOpen = false; + await goto("/main"); } // Cleanup on unmount diff --git a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte index 6628964f5..34bdd6b6d 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte @@ -233,16 +233,34 @@ onMount(async () => { } }; + // Validation function for demo name + const isValidName = (name: string): boolean => { + if (!name) return false; + const trimmed = name.trim(); + if (trimmed.length === 0) return false; + // Check if name is not just whitespace, newlines, or enter characters + if (/^[\s\n\r]+$/.test(trimmed)) return false; + return true; + }; + // New function to handle final submission with demo name handleFinalSubmit = async () => { + // Validate name before proceeding + const trimmedName = demoName.trim(); + if (!isValidName(trimmedName)) { + error = "Please enter a valid name (cannot be empty or only spaces)"; + setTimeout(() => { + error = null; + }, 5000); + return; + } + loading = true; const tenYearsLater = new Date(); tenYearsLater.setFullYear(tenYearsLater.getFullYear() + 10); globalState.userController.user = { - name: - demoName || - capitalize(`${falso.randFirstName()} ${falso.randLastName()}`), + name: trimmedName || capitalize(`${falso.randFirstName()} ${falso.randLastName()}`), "Date of Birth": new Date().toDateString(), "ID submitted": `Passport - ${falso.randCountryCode()}`, "Passport Number": generatePassportNumber(), @@ -350,13 +368,19 @@ onMount(async () => { { + demoName = (e.target as HTMLInputElement).value; + }} class="border-1 border-gray-200 w-full rounded-md font-medium my-2 p-2" placeholder="Enter your demo name for ePassport" /> + {#if error && error.includes("name")} +

{error}

+ {/if}
Continue diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte index d2f042f26..a884365c1 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte @@ -12,7 +12,7 @@ import { ButtonAction } from "$lib/ui"; import Drawer from "$lib/ui/Drawer/Drawer.svelte"; import { capitalize } from "$lib/utils"; import axios from "axios"; -import { getContext, onMount } from "svelte"; +import { getContext, onMount, setContext } from "svelte"; import { Shadow } from "svelte-loading-spinners"; import { v4 as uuidv4 } from "uuid"; import DocumentType from "./steps/document-type.svelte"; @@ -253,6 +253,16 @@ onMount(async () => { globalState = getContext<() => GlobalState>("globalState")(); // handle verification logic + sec user data in the store + // Provide showVeriffModal context to child components + setContext("showVeriffModal", { + get value() { + return showVeriffModal; + }, + set value(v: boolean) { + showVeriffModal = v; + }, + }); + // Check hardware key support first await checkHardwareKeySupport(); @@ -391,7 +401,7 @@ onMount(async () => { >I'm ready {/if} - +
{#if $verifStep === 0} diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte index 51ca2b28b..aa3fc4f3c 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte @@ -1,17 +1,40 @@
-
-

Choose Document Type

-

Select the type of identity document you will be presenting

+
+ +
+

Choose Document Type

+

Select the type of identity document you will be presenting

+
diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte index 30294edd3..ab25bb1e4 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte @@ -1,6 +1,8 @@ {#if showSplashScreen} @@ -451,6 +537,8 @@ $effect(() => {
{/if} + + - From a0be3caae918ca0db647cbf400657cf9c97cdae9 Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 00:34:47 +0530 Subject: [PATCH 06/21] fix: make toast account for safe area height --- infrastructure/eid-wallet/src/lib/ui/Toast/Toast.svelte | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infrastructure/eid-wallet/src/lib/ui/Toast/Toast.svelte b/infrastructure/eid-wallet/src/lib/ui/Toast/Toast.svelte index 4d7e12f4d..3748330da 100644 --- a/infrastructure/eid-wallet/src/lib/ui/Toast/Toast.svelte +++ b/infrastructure/eid-wallet/src/lib/ui/Toast/Toast.svelte @@ -38,7 +38,8 @@
{#each toasts as toast (toast.id)}
Date: Wed, 10 Dec 2025 00:36:33 +0530 Subject: [PATCH 07/21] feat: add eye icon back to ePassport card --- .../lib/fragments/IdentityCard/IdentityCard.svelte | 11 +++++++++++ .../eid-wallet/src/routes/(app)/main/+page.svelte | 1 + 2 files changed, 12 insertions(+) diff --git a/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte b/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte index 69f9ceb5a..35656edec 100644 --- a/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte +++ b/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte @@ -5,6 +5,7 @@ import { toast } from "$lib/ui/Toast/toast"; import { CheckmarkBadge02Icon, Copy01Icon, + ViewIcon, } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/svelte"; import type { HTMLAttributes } from "svelte/elements"; @@ -15,6 +16,7 @@ interface userData { interface IIdentityCard extends HTMLAttributes { variant?: "eName" | "ePassport" | "eVault"; userId?: string; + viewBtn?: () => void; userData?: userData; totalStorage?: number; usedStorage?: number; @@ -23,6 +25,7 @@ interface IIdentityCard extends HTMLAttributes { const { variant = "eName", userId, + viewBtn, userData, totalStorage = 0, usedStorage = 0, @@ -88,6 +91,14 @@ const baseClasses = `relative ${variant === "eName" ? "bg-black-900" : variant = {userData.isFake ? "DEMO ID" : "VERIFIED ID"} {/if}

+ {#if viewBtn} + + {/if} {:else if variant === "eVault"}

{state.progressWidth} Used diff --git a/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte index 2637e5513..1b33f740e 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte @@ -133,6 +133,7 @@ onDestroy(() => { {#snippet ePassport()} goto("/ePassport")} userData={userData as Record} /> {/snippet} From 0d5313aef75ad920d9d3abb497a28ac582344270 Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 00:40:56 +0530 Subject: [PATCH 08/21] fix: drawer --- .../src/lib/ui/Drawer/Drawer.svelte | 24 ++++++++++++------- .../src/routes/(auth)/verify/+page.svelte | 2 +- .../(auth)/verify/steps/passport.svelte | 8 +++---- .../routes/(auth)/verify/steps/selfie.svelte | 6 ++--- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte b/infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte index 44bf14a64..2dab8f766 100644 --- a/infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte +++ b/infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte @@ -53,8 +53,11 @@ const swipe = swipeResult.swipe as any; // Initialize pane only once when element is available $effect(() => { if (!drawerElem) return; + const screenHeight = window.innerHeight; + const fullScreenHeight = Math.floor(screenHeight * 0.9); // 90vh + pane = new CupertinoPane(drawerElem, { - fitHeight: true, + fitHeight: fullScreen, backdrop: true, backdropOpacity: dismissible ? 0.5 : 0.8, backdropBlur: true, @@ -68,10 +71,14 @@ $effect(() => { isPaneOpen = false; }, }, - breaks: { - bottom: { enabled: true, height: 250 }, - }, - initialBreak: "bottom", + breaks: fullScreen + ? { + top: { enabled: true, height: fullScreenHeight }, + } + : { + bottom: { enabled: true, height: 250 }, + }, + initialBreak: fullScreen ? "top" : "bottom", }); // Add class to pane element based on fullScreen prop @@ -165,10 +172,11 @@ $effect(() => { :global(.pane.drawer-fullscreen) { width: 100% !important; - max-height: 100vh !important; - min-height: 100vh !important; - height: 100vh !important; + max-height: 90vh !important; + min-height: 90vh !important; + height: 90vh !important; bottom: 0 !important; + top: auto !important; border-radius: 0 !important; padding-block-start: 0 !important; padding-block-end: 0 !important; diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte index a884365c1..21a3f5c23 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte @@ -402,7 +402,7 @@ onMount(async () => { > {/if} -
+
{#if $verifStep === 0} {:else if $verifStep === 1} diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte index ab25bb1e4..4938b2b2d 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte @@ -225,18 +225,18 @@ onMount(() => { {error}
{/if} -
+
-
+
verifStep.set(0)} - class="cursor-pointer mt-1" + class="cursor-pointer self-start" /> -
+

{#if $documentType === "passport"} Present your Passport diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte index 6fcd1f4c6..4af184294 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte @@ -73,15 +73,15 @@ async function captureImage() {
{#if !load} -
+
verifStep.set(1)} - class="cursor-pointer mt-1" + class="cursor-pointer self-start" /> -
+

Take a Selfie

Place your face in the center of the circle and press the take From f9ddf9dcfa57172b5514715913f1f06c95c8035d Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 00:47:18 +0530 Subject: [PATCH 09/21] feat: change the drawer to page for verirication --- .../src/lib/ui/Drawer/Drawer.svelte | 74 ++++++++++++++----- .../src/routes/(auth)/verify/+page.svelte | 10 +-- .../(auth)/verify/passport/+page.svelte | 8 ++ .../routes/(auth)/verify/selfie/+page.svelte | 8 ++ .../(auth)/verify/steps/document-type.svelte | 7 ++ .../(auth)/verify/steps/passport.svelte | 10 ++- .../routes/(auth)/verify/steps/selfie.svelte | 30 ++++++-- 7 files changed, 112 insertions(+), 35 deletions(-) create mode 100644 infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte create mode 100644 infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte diff --git a/infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte b/infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte index 2dab8f766..ac827f74e 100644 --- a/infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte +++ b/infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte @@ -50,11 +50,17 @@ const swipe = swipeResult.swipe as any; // isPaneOpen = false; // }; -// Initialize pane only once when element is available +// Initialize pane - destroy and recreate when fullScreen changes $effect(() => { if (!drawerElem) return; + + // Destroy existing pane if it exists + if (pane) { + pane.destroy(); + } + const screenHeight = window.innerHeight; - const fullScreenHeight = Math.floor(screenHeight * 0.9); // 90vh + const fullScreenHeight = Math.floor(screenHeight * 0.8); // 80vh pane = new CupertinoPane(drawerElem, { fitHeight: fullScreen, @@ -96,27 +102,52 @@ $effect(() => { } }, 0); - return () => pane?.destroy(); + return () => { + if (pane) { + pane.destroy(); + } + }; }); // Handle open/close state separately $effect(() => { - if (!pane) return; - - // Update fullscreen class when prop changes - const paneElement = document.querySelector(".pane") as HTMLElement; - if (paneElement) { - if (fullScreen) { - paneElement.classList.add("drawer-fullscreen"); - paneElement.classList.remove("drawer-normal"); - } else { - paneElement.classList.add("drawer-normal"); - paneElement.classList.remove("drawer-fullscreen"); - } - } + if (!pane || !drawerElem) return; if (isPaneOpen) { + // Ensure pane exists before presenting + if (!pane.pane || !document.querySelector(".pane")) { + // Recreate pane if it was destroyed + const screenHeight = window.innerHeight; + const fullScreenHeight = Math.floor(screenHeight * 0.8); + pane.destroy(); + pane = new CupertinoPane(drawerElem, { + fitHeight: fullScreen, + backdrop: true, + backdropOpacity: dismissible ? 0.5 : 0.8, + backdropBlur: true, + bottomClose: dismissible, + buttonDestroy: false, + showDraggable: dismissible, + upperThanTop: true, + events: { + onBackdropTap: () => { + pane?.destroy(); + isPaneOpen = false; + }, + }, + breaks: fullScreen + ? { + top: { enabled: true, height: fullScreenHeight }, + } + : { + bottom: { enabled: true, height: 250 }, + }, + initialBreak: fullScreen ? "top" : "bottom", + }); + } + pane.present({ animate: true }); + // Update class after presenting setTimeout(() => { const paneEl = document.querySelector(".pane") as HTMLElement; @@ -131,7 +162,10 @@ $effect(() => { } }, 0); } else { - pane.destroy({ animate: true }); + // Don't destroy, just hide - this keeps the pane available + if (pane.pane) { + pane.hide(); + } } }); @@ -172,9 +206,9 @@ $effect(() => { :global(.pane.drawer-fullscreen) { width: 100% !important; - max-height: 90vh !important; - min-height: 90vh !important; - height: 90vh !important; + max-height: 80vh !important; + min-height: 80vh !important; + height: 80vh !important; bottom: 0 !important; top: auto !important; border-radius: 0 !important; diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte index 21a3f5c23..99f8a9e6a 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte @@ -16,8 +16,6 @@ import { getContext, onMount, setContext } from "svelte"; import { Shadow } from "svelte-loading-spinners"; import { v4 as uuidv4 } from "uuid"; import DocumentType from "./steps/document-type.svelte"; -import Passport from "./steps/passport.svelte"; -import Selfie from "./steps/selfie.svelte"; import { DocBack, DocFront, @@ -172,6 +170,8 @@ function watchEventStream(id: string) { SelfiePic.set(null); } verifStep.set(3); + // Show drawer with results + showVeriffModal = true; }; } @@ -401,14 +401,10 @@ onMount(async () => { >I'm ready {/if} - +

{#if $verifStep === 0} - {:else if $verifStep === 1} - - {:else if $verifStep === 2} - {:else if loading}
+import Passport from "../steps/passport.svelte"; + + +
+ +
+ diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte new file mode 100644 index 000000000..3dc1b000f --- /dev/null +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte @@ -0,0 +1,8 @@ + + +
+ +
+ diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte index aa3fc4f3c..259b405df 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte @@ -7,9 +7,16 @@ import { getContext } from "svelte"; let showVeriffModal = getContext<{ value: boolean }>("showVeriffModal"); +import { goto } from "$app/navigation"; + function selectDocumentType(type: "passport" | "id" | "permit" | "dl") { documentType.set(type); verifStep.set(1); // Move to document capture step + // Close drawer and navigate to fullscreen passport page + if (showVeriffModal) { + showVeriffModal.value = false; + } + goto("/verify/passport"); } function goBack() { diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte index 4938b2b2d..8c942a24d 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte @@ -3,6 +3,7 @@ import { PUBLIC_PROVISIONER_URL } from "$env/static/public"; import { ButtonAction } from "$lib/ui"; import * as Button from "$lib/ui/Button"; import { ArrowLeft01Icon } from "@hugeicons/core-free-icons"; +import { goto } from "$app/navigation"; import axios from "axios"; import { onMount } from "svelte"; import { writable } from "svelte/store"; @@ -206,7 +207,7 @@ function stopCamera() { function continueToSelfie() { stopCamera(); - verifStep.set(2); + goto("/verify/selfie"); } onMount(() => { @@ -233,7 +234,10 @@ onMount(() => { icon={ArrowLeft01Icon} iconColor="black" strokeWidth={2} - onclick={() => verifStep.set(0)} + onclick={() => { + stopCamera(); + goto("/verify"); + }} class="cursor-pointer self-start" />
@@ -273,7 +277,7 @@ onMount(() => { -
+
{#if $documentType === "passport"} Present your Passport's photo page diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte index 4af184294..012b27913 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte @@ -3,6 +3,7 @@ import { PUBLIC_PROVISIONER_URL } from "$env/static/public"; import { ButtonAction } from "$lib/ui"; import * as Button from "$lib/ui/Button"; import { ArrowLeft01Icon } from "@hugeicons/core-free-icons"; +import { goto } from "$app/navigation"; import axios from "axios"; import { onMount } from "svelte"; import { Shadow } from "svelte-loading-spinners"; @@ -30,8 +31,20 @@ async function requestCameraPermission() { } } +function stopCamera() { + if (stream) { + for (const track of stream.getTracks()) { + track.stop(); + } + } +} + onMount(() => { requestCameraPermission(); + + return () => { + stopCamera(); + }; }); async function captureImage() { @@ -61,9 +74,9 @@ async function captureImage() { PUBLIC_PROVISIONER_URL, ).toString(), ); - for (const track of stream.getTracks()) { - track.stop(); - } + stopCamera(); + // Navigate back to verify page to show results in drawer + goto("/verify"); // The verification step will be updated by the SSE response // verifStep will be set to 3 by the websocket event } @@ -78,7 +91,14 @@ async function captureImage() { icon={ArrowLeft01Icon} iconColor="black" strokeWidth={2} - onclick={() => verifStep.set(1)} + onclick={() => { + if (stream) { + for (const track of stream.getTracks()) { + track.stop(); + } + } + goto("/verify/passport"); + }} class="cursor-pointer self-start" />
@@ -114,7 +134,7 @@ async function captureImage() {
-
+
Please make sure that your face is in the frame and clearly visible.
From 8c96e230d03d9fce5b54a81f8607eea8eec3ae37 Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 00:50:07 +0530 Subject: [PATCH 10/21] chore: ux improvments to onboarding --- .../eid-wallet/src/routes/(auth)/verify/passport/+page.svelte | 2 +- .../eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte | 2 +- .../eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte index 82cb4afe0..72837ee9a 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte @@ -2,7 +2,7 @@ import Passport from "../steps/passport.svelte"; -
+
diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte index 3dc1b000f..8be1907dd 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte @@ -2,7 +2,7 @@ import Selfie from "../steps/selfie.svelte"; -
+
diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte index 012b27913..e66c8d2d0 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte @@ -142,9 +142,9 @@ async function captureImage() { >{"Take Photo"} {:else} -
+

Verifying your identity

From 47c2919e16561f1b0a56ab557bd643ab02470c1e Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 00:53:00 +0530 Subject: [PATCH 11/21] chore: fix redirect --- infrastructure/eid-wallet/package.json | 4 ++-- infrastructure/eid-wallet/src-tauri/tauri.conf.json | 10 ++++++---- .../eid-wallet/src/routes/(auth)/verify/+page.svelte | 8 +++++++- .../src/routes/(auth)/verify/steps/selfie.svelte | 4 ++-- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/infrastructure/eid-wallet/package.json b/infrastructure/eid-wallet/package.json index 43757b491..0642fc32a 100644 --- a/infrastructure/eid-wallet/package.json +++ b/infrastructure/eid-wallet/package.json @@ -1,6 +1,6 @@ { "name": "eid-wallet", - "version": "0.4.0", + "version": "0.5.0", "description": "", "type": "module", "scripts": { @@ -83,4 +83,4 @@ "vite-plugin-node-polyfills": "^0.24.0", "vitest": "^3.0.9" } -} +} \ No newline at end of file diff --git a/infrastructure/eid-wallet/src-tauri/tauri.conf.json b/infrastructure/eid-wallet/src-tauri/tauri.conf.json index e9185048a..3736e7cc2 100644 --- a/infrastructure/eid-wallet/src-tauri/tauri.conf.json +++ b/infrastructure/eid-wallet/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "eID for W3DS", - "version": "0.4.0", + "version": "0.5.0", "identifier": "foundation.metastate.eid-wallet", "build": { "beforeDevCommand": "pnpm dev", @@ -18,7 +18,9 @@ } ], "security": { - "capabilities": ["mobile-capability"], + "capabilities": [ + "mobile-capability" + ], "csp": null } }, @@ -26,7 +28,7 @@ "active": true, "targets": "all", "android": { - "versionCode": 12 + "versionCode": 20 }, "icon": [ "icons/32x32.png", @@ -36,4 +38,4 @@ "icons/icon.ico" ] } -} +} \ No newline at end of file diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte index 99f8a9e6a..3fd84379f 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte @@ -170,8 +170,9 @@ function watchEventStream(id: string) { SelfiePic.set(null); } verifStep.set(3); - // Show drawer with results + // Navigate to verify page and show drawer with results immediately showVeriffModal = true; + goto("/verify"); }; } @@ -253,6 +254,11 @@ onMount(async () => { globalState = getContext<() => GlobalState>("globalState")(); // handle verification logic + sec user data in the store + // If verification is complete (step 3), show drawer immediately + if ($verifStep === 3) { + showVeriffModal = true; + } + // Provide showVeriffModal context to child components setContext("showVeriffModal", { get value() { diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte index e66c8d2d0..3c7238c82 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte @@ -75,10 +75,10 @@ async function captureImage() { ).toString(), ); stopCamera(); - // Navigate back to verify page to show results in drawer - goto("/verify"); + // Stay on this page and show spinner // The verification step will be updated by the SSE response // verifStep will be set to 3 by the websocket event + // When results are ready, the verify page will handle showing the drawer } } } From 691347cef1be263a0ed4c829a75a82445d45d949 Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 00:53:38 +0530 Subject: [PATCH 12/21] chore: bump versions --- .../src/routes/(app)/settings/+page.svelte | 207 +++++++++--------- 1 file changed, 104 insertions(+), 103 deletions(-) diff --git a/infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte index c485056c0..90e3088b4 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte @@ -1,114 +1,115 @@
@@ -140,7 +141,7 @@ $effect(() => { onclick={handleVersionTap} disabled={isRetrying} > - Version v0.4.0.0 + Version v0.5.0.0 {#if retryMessage} From 571daa356a2204b5a0070888b18b99e644a206db Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 00:54:52 +0530 Subject: [PATCH 13/21] chore: margins --- .../eid-wallet/src/routes/(auth)/verify/passport/+page.svelte | 2 +- .../eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte index 72837ee9a..25cb45bd8 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte @@ -2,7 +2,7 @@ import Passport from "../steps/passport.svelte"; -
+
diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte index 8be1907dd..7662dc435 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte @@ -2,7 +2,7 @@ import Selfie from "../steps/selfie.svelte"; -
+
From fb5c8e6dee7127f745d42f873da23ca55fff9cc1 Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 00:56:13 +0530 Subject: [PATCH 14/21] fix: inset margins --- .../eid-wallet/src/routes/(auth)/verify/passport/+page.svelte | 2 +- .../eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte index 25cb45bd8..be28b7695 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte @@ -2,7 +2,7 @@ import Passport from "../steps/passport.svelte"; -
+
diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte index 7662dc435..dde1fba85 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte @@ -2,7 +2,7 @@ import Selfie from "../steps/selfie.svelte"; -
+
From 625921baa5f31cf78a68d387af34ac44901ce63e Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 00:57:34 +0530 Subject: [PATCH 15/21] fix: top padding inset on picture pages --- .../eid-wallet/src/routes/(auth)/verify/passport/+page.svelte | 2 +- .../eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte index be28b7695..23040e08e 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/passport/+page.svelte @@ -2,7 +2,7 @@ import Passport from "../steps/passport.svelte"; -
+
diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte index dde1fba85..387e15e26 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/selfie/+page.svelte @@ -2,7 +2,7 @@ import Selfie from "../steps/selfie.svelte"; -
+
From feb782899412fe81ad7f085119fc283656b8ff9e Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 00:59:14 +0530 Subject: [PATCH 16/21] fix: back buttons --- .../(auth)/verify/steps/passport.svelte | 19 ++++++++++++------- .../routes/(auth)/verify/steps/selfie.svelte | 17 +++++++++++------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte index 8c942a24d..5ae18d1fd 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte @@ -230,16 +230,21 @@ onMount(() => {
- { stopCamera(); goto("/verify"); }} - class="cursor-pointer self-start" - /> + class="cursor-pointer self-start flex items-center gap-2 text-sm text-gray-600 hover:text-gray-800" + > + + go back +

{#if $documentType === "passport"} @@ -323,7 +328,7 @@ onMount(() => { callback={continueToSelfie} class="flex-1" color="primary" - >Continue to SelfieContinue

{:else} diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte index 3c7238c82..a0592182a 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte @@ -87,10 +87,7 @@ async function captureImage() {
{#if !load}
- { if (stream) { for (const track of stream.getTracks()) { @@ -99,8 +96,16 @@ async function captureImage() { } goto("/verify/passport"); }} - class="cursor-pointer self-start" - /> + class="cursor-pointer self-start flex items-center gap-2 text-sm text-gray-600 hover:text-gray-800" + > + + go back +

Take a Selfie

From 5485dc66c6b3abc2a67f8f8e61b7313feecf7baf Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 01:02:50 +0530 Subject: [PATCH 17/21] fix: back button consistency --- .../(auth)/verify/steps/document-type.svelte | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte index 259b405df..a6fe5940c 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte @@ -30,14 +30,19 @@ function goBack() {

-
- +

Choose Document Type

Select the type of identity document you will be presenting

From cc975a5c998606f560cbbea0060d6de8f8f9912a Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 01:21:31 +0530 Subject: [PATCH 18/21] fix: ux issues --- .../IdentityCard/IdentityCard.svelte | 8 +- .../src/lib/ui/Drawer/Drawer.svelte | 110 +--------- .../src/routes/(app)/scan-qr/+page.svelte | 8 +- .../src/routes/(auth)/verify/+page.svelte | 71 ++----- .../(auth)/verify/steps/document-type.svelte | 4 +- .../(auth)/verify/steps/passport.svelte | 2 +- .../routes/(auth)/verify/steps/selfie.svelte | 193 ++++++++++++++++-- 7 files changed, 215 insertions(+), 181 deletions(-) diff --git a/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte b/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte index 35656edec..cc7d66116 100644 --- a/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte +++ b/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte @@ -67,10 +67,10 @@ const baseClasses = `relative ${variant === "eName" ? "bg-black-900" : variant = className="text-secondary" icon={CheckmarkBadge02Icon} /> - { if (userId) { try { @@ -82,7 +82,7 @@ const baseClasses = `relative ${variant === "eName" ? "bg-black-900" : variant = } } }} - /> + /> {:else if variant === "ePassport"}

{ children?: Snippet; handleSwipe?: (isOpen: boolean | undefined) => void; dismissible?: boolean; - fullScreen?: boolean; } let drawerElem: HTMLDivElement; @@ -22,7 +21,6 @@ let { children = undefined, handleSwipe, dismissible = true, - fullScreen = false, ...restProps }: IDrawerProps = $props(); @@ -50,20 +48,11 @@ const swipe = swipeResult.swipe as any; // isPaneOpen = false; // }; -// Initialize pane - destroy and recreate when fullScreen changes +// Initialize pane $effect(() => { if (!drawerElem) return; - // Destroy existing pane if it exists - if (pane) { - pane.destroy(); - } - - const screenHeight = window.innerHeight; - const fullScreenHeight = Math.floor(screenHeight * 0.8); // 80vh - pane = new CupertinoPane(drawerElem, { - fitHeight: fullScreen, backdrop: true, backdropOpacity: dismissible ? 0.5 : 0.8, backdropBlur: true, @@ -77,31 +66,12 @@ $effect(() => { isPaneOpen = false; }, }, - breaks: fullScreen - ? { - top: { enabled: true, height: fullScreenHeight }, - } - : { - bottom: { enabled: true, height: 250 }, - }, - initialBreak: fullScreen ? "top" : "bottom", + breaks: { + bottom: { enabled: true, height: 250 }, + }, + initialBreak: "bottom", }); - // Add class to pane element based on fullScreen prop - // Use setTimeout to ensure pane element is created - setTimeout(() => { - const paneElement = document.querySelector(".pane") as HTMLElement; - if (paneElement) { - if (fullScreen) { - paneElement.classList.add("drawer-fullscreen"); - paneElement.classList.remove("drawer-normal"); - } else { - paneElement.classList.add("drawer-normal"); - paneElement.classList.remove("drawer-fullscreen"); - } - } - }, 0); - return () => { if (pane) { pane.destroy(); @@ -114,53 +84,7 @@ $effect(() => { if (!pane || !drawerElem) return; if (isPaneOpen) { - // Ensure pane exists before presenting - if (!pane.pane || !document.querySelector(".pane")) { - // Recreate pane if it was destroyed - const screenHeight = window.innerHeight; - const fullScreenHeight = Math.floor(screenHeight * 0.8); - pane.destroy(); - pane = new CupertinoPane(drawerElem, { - fitHeight: fullScreen, - backdrop: true, - backdropOpacity: dismissible ? 0.5 : 0.8, - backdropBlur: true, - bottomClose: dismissible, - buttonDestroy: false, - showDraggable: dismissible, - upperThanTop: true, - events: { - onBackdropTap: () => { - pane?.destroy(); - isPaneOpen = false; - }, - }, - breaks: fullScreen - ? { - top: { enabled: true, height: fullScreenHeight }, - } - : { - bottom: { enabled: true, height: 250 }, - }, - initialBreak: fullScreen ? "top" : "bottom", - }); - } - pane.present({ animate: true }); - - // Update class after presenting - setTimeout(() => { - const paneEl = document.querySelector(".pane") as HTMLElement; - if (paneEl) { - if (fullScreen) { - paneEl.classList.add("drawer-fullscreen"); - paneEl.classList.remove("drawer-normal"); - } else { - paneEl.classList.add("drawer-normal"); - paneEl.classList.remove("drawer-fullscreen"); - } - } - }, 0); } else { // Don't destroy, just hide - this keeps the pane available if (pane.pane) { @@ -174,7 +98,7 @@ $effect(() => { {...restProps} use:swipe bind:this={drawerElem} - class={cn(restProps.class, fullScreen ? "drawer-fullscreen" : "drawer-normal")} + class={cn(restProps.class)} >

{@render children?.()} @@ -187,13 +111,9 @@ $effect(() => { left: 50% !important; transform: translateX(-50%) !important; background-color: var(--color-white) !important; - overflow-y: auto !important; /* vertical scroll if needed */ - overflow-x: hidden !important; /* prevent sideways scroll */ - -webkit-overflow-scrolling: touch; /* smooth scrolling on iOS */ - } - - :global(.pane.drawer-normal), - :global(.pane:not(.drawer-fullscreen)) { + overflow-y: auto !important; + overflow-x: hidden !important; + -webkit-overflow-scrolling: touch; width: 95% !important; max-height: 600px !important; min-height: 250px !important; @@ -204,18 +124,6 @@ $effect(() => { padding-block-end: 20px !important; } - :global(.pane.drawer-fullscreen) { - width: 100% !important; - max-height: 80vh !important; - min-height: 80vh !important; - height: 80vh !important; - bottom: 0 !important; - top: auto !important; - border-radius: 0 !important; - padding-block-start: 0 !important; - padding-block-end: 0 !important; - } - :global(.move) { display: none !important; margin-block: 6px !important; diff --git a/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte index c594628de..74d8ae7da 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte @@ -100,8 +100,8 @@ $effect(() => { async function handleAuthDrawerDecline() { // Cancel button always navigates to main dashboard - setCodeScannedDrawerOpen(false); - await goto("/main"); + setCodeScannedDrawerOpen(false); + await goto("/main"); } function handleAuthDrawerOpenChange(value: boolean) { @@ -121,8 +121,8 @@ function handleLoggedInDrawerOpenChange(value: boolean) { async function handleSigningDrawerDecline() { // Cancel button always navigates to main dashboard - setSigningDrawerOpen(false); - await goto("/main"); + setSigningDrawerOpen(false); + await goto("/main"); } function handleSigningDrawerOpenChange(value: boolean) { diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte index 3fd84379f..8c1f5cbf3 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte @@ -170,9 +170,8 @@ function watchEventStream(id: string) { SelfiePic.set(null); } verifStep.set(3); - // Navigate to verify page and show drawer with results immediately - showVeriffModal = true; - goto("/verify"); + // Data is now available in stores for selfie page to use + // Don't navigate - stay on selfie page which will show results }; } @@ -254,11 +253,6 @@ onMount(async () => { globalState = getContext<() => GlobalState>("globalState")(); // handle verification logic + sec user data in the store - // If verification is complete (step 3), show drawer immediately - if ($verifStep === 3) { - showVeriffModal = true; - } - // Provide showVeriffModal context to child components setContext("showVeriffModal", { get value() { @@ -269,6 +263,19 @@ onMount(async () => { }, }); + // Provide verification data context for selfie page + setContext("verifyData", { + get person() { + return person; + }, + get document() { + return document; + }, + get websocketData() { + return websocketData; + }, + }); + // Check hardware key support first await checkHardwareKeySupport(); @@ -411,54 +418,6 @@ onMount(async () => {
{#if $verifStep === 0} - {:else if loading} -
-
- -

Generating your eName

-
-
- {:else} -
- {#if $status === "approved"} -
-

Your verification was a success

-

You can now continue on to create your eName

-
- {:else if $status === "duplicate"} -
-

Old eVault Found

-

- We found an existing eVault associated with your - identity. You can claim it back to continue - using your account. -

-
- {:else if $status === "resubmission_requested"} -

Your verification failed due to the reason

-

{$reason}

- {:else} -

Your verification failed

- -

{$reason}

- {/if} -
-
- {#if $status !== "declined"} - {$status === "approved" - ? "Continue" - : $status === "duplicate" - ? "Claim old eVault" - : "Retry"} - {/if} -
{/if}
diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte index a6fe5940c..e97db08d9 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/document-type.svelte @@ -44,8 +44,8 @@ function goBack() { go back
-

Choose Document Type

-

Select the type of identity document you will be presenting

+

Choose Document Type

+

Select the type of identity document you will be presenting

diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte index 5ae18d1fd..2bb9e400f 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/passport.svelte @@ -246,7 +246,7 @@ onMount(() => { go back
-

+

{#if $documentType === "passport"} Present your Passport {:else if $documentType === "id"} diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte index a0592182a..4d52d0d7b 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte @@ -1,14 +1,17 @@
- {#if !load} + {#if !load && !showResults}
-
-

Take a Selfie

-

- Place your face in the center of the circle and press the take - photo button -

+
+

Take a Selfie

+

+ Place your face in the center of the circle and press the take + photo button +

@@ -146,7 +261,7 @@ async function captureImage() { {"Take Photo"} - {:else} + {:else if load && !showResults}
Verifying your identity

+ {:else if showResults} +
+ {#if loading} +
+ +

Setting up your account

+
+ {:else} + {#if $status === "approved"} +
+

Your verification was a success

+

You can now continue to create your eName

+
+ {:else if $status === "duplicate"} +
+

Old eVault Found

+

+ We found an existing eVault associated with your + identity. You can claim it back to continue + using your account. +

+
+ {:else if $status === "resubmission_requested"} +
+

Your verification failed

+

{$reason}

+
+ {:else} +
+

Your verification failed

+

{$reason}

+
+ {/if} + +
+ {#if $status !== "declined"} + + {$status === "approved" + ? "Continue" + : $status === "duplicate" + ? "Claim old eVault" + : "Retry"} + + {/if} +
+ {/if} +
{/if}
From 3c9482a240b85f1d53f7a7825b270fc996f8570c Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 01:25:11 +0530 Subject: [PATCH 19/21] chore: move user data to stores --- .../src/routes/(auth)/verify/+page.svelte | 7 ++++ .../routes/(auth)/verify/steps/selfie.svelte | 40 ++++++++----------- .../src/routes/(auth)/verify/store.ts | 3 ++ 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte index 8c1f5cbf3..5d5a503f3 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte @@ -24,6 +24,9 @@ import { status, verifStep, verificaitonId, + verificationPerson, + verificationDocument, + verificationWebsocketData, } from "./store"; type Document = { @@ -164,6 +167,10 @@ function watchEventStream(id: string) { person = data.person; document = data.document; websocketData = data; // Store the full websocket data + // Also store in writable stores for selfie page + verificationPerson.set(data.person); + verificationDocument.set(data.document); + verificationWebsocketData.set(data); if (data.status === "resubmission_requested") { DocFront.set(null); DocBack.set(null); diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte index 4d52d0d7b..1c0fabf6f 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte @@ -8,7 +8,7 @@ import axios from "axios"; import { getContext, onMount } from "svelte"; import { Shadow } from "svelte-loading-spinners"; import { writable } from "svelte/store"; -import { Selfie, permissionGranted, verifStep, verificaitonId, status, reason } from "../store"; +import { Selfie, permissionGranted, verifStep, verificaitonId, status, reason, verificationPerson, verificationDocument, verificationWebsocketData } from "../store"; import type { GlobalState } from "$lib/global"; import { capitalize } from "$lib/utils"; import { v4 as uuidv4 } from "uuid"; @@ -23,11 +23,6 @@ let showResults = $state(false); let loading = $state(false); let globalState: GlobalState | undefined = $state(undefined); -// Store websocket data -let person: any = $state(null); -let document: any = $state(null); -let websocketData: { w3id?: string } | null = $state(null); - async function requestCameraPermission() { try { stream = await navigator.mediaDevices.getUserMedia({ @@ -54,13 +49,6 @@ function stopCamera() { $effect(() => { if ($status && $verifStep === 3) { showResults = true; - // Get person/document data from context if needed - const verifyContext = getContext("verifyData"); - if (verifyContext) { - person = verifyContext.person; - document = verifyContext.document; - websocketData = verifyContext.websocketData; - } } }); @@ -120,33 +108,37 @@ async function handleContinue() { return verifStep.set(0); } if (!globalState) throw new Error("Global state is not defined"); + if (!$verificationPerson || !$verificationDocument) { + console.error("Missing verification data"); + return; + } loading = true; try { globalState.userController.user = { name: capitalize( - `${person.firstName.value} ${person.lastName.value ?? ""}`, + `${$verificationPerson.firstName.value} ${$verificationPerson.lastName.value ?? ""}`, ), - "Date of Birth": new Date(person.dateOfBirth.value).toDateString(), + "Date of Birth": new Date($verificationPerson.dateOfBirth.value).toDateString(), "ID submitted": - document.type.value === "passport" - ? `Passport - ${document.country.value}` - : document.type.value === "drivers_license" - ? `Driving License - ${document.country.value}` - : `ID Card - ${document.country.value}`, - "Document Number": document.number.value, + $verificationDocument.type.value === "passport" + ? `Passport - ${$verificationDocument.country.value}` + : $verificationDocument.type.value === "drivers_license" + ? `Driving License - ${$verificationDocument.country.value}` + : `ID Card - ${$verificationDocument.country.value}`, + "Document Number": $verificationDocument.number.value, }; globalState.userController.document = { - "Valid From": new Date(document.validFrom.value).toDateString(), - "Valid Until": new Date(document.validUntil.value).toDateString(), + "Valid From": new Date($verificationDocument.validFrom.value).toDateString(), + "Valid Until": new Date($verificationDocument.validUntil.value).toDateString(), "Verified On": new Date().toDateString(), }; globalState.userController.isFake = false; if ($status === "duplicate") { // For duplicate case, skip provision and resolve the existing eVault URI - const existingW3id = websocketData?.w3id; + const existingW3id = $verificationWebsocketData?.w3id; if (!existingW3id) { throw new Error("No w3id provided for duplicate eVault"); } diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/store.ts b/infrastructure/eid-wallet/src/routes/(auth)/verify/store.ts index 1f1e29f3a..3e96441b9 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/store.ts +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/store.ts @@ -11,3 +11,6 @@ export const reason = writable(); export const documentType = writable< "passport" | "id" | "permit" | "dl" | null >(null); +export const verificationPerson = writable(null); +export const verificationDocument = writable(null); +export const verificationWebsocketData = writable<{ w3id?: string } | null>(null); From a977ab716006e21e8e60d1643873f9d5ec79ee68 Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 01:30:45 +0530 Subject: [PATCH 20/21] fix: selfie page --- .../routes/(auth)/verify/steps/selfie.svelte | 78 ++++++++++++------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte index 1c0fabf6f..8098a9fe6 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte @@ -65,33 +65,39 @@ async function captureImage() { if (image === 1) { const context = canvas.getContext("2d"); if (context) { - context.drawImage(video, 0, 0, 1920, 1080); - canvas.width = video.videoWidth; - canvas.height = video.videoHeight; - context.drawImage(video, 0, 0, canvas.width, canvas.height); - const dataUrl = canvas.toDataURL("image/png"); - Selfie.set(dataUrl); - load = true; - await axios.post( - new URL( - `/verification/${$verificaitonId}/media`, - PUBLIC_PROVISIONER_URL, - ).toString(), - { - img: dataUrl, - type: "face", - }, - ); - await axios.patch( - new URL( - `/verification/${$verificaitonId}`, - PUBLIC_PROVISIONER_URL, - ).toString(), - ); - stopCamera(); - // Stay on this page and show spinner - // The verification step will be updated by the SSE response - // When status is set, showResults will be true + load = true; // Show loading immediately + try { + context.drawImage(video, 0, 0, 1920, 1080); + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + context.drawImage(video, 0, 0, canvas.width, canvas.height); + const dataUrl = canvas.toDataURL("image/png"); + Selfie.set(dataUrl); + + await axios.post( + new URL( + `/verification/${$verificaitonId}/media`, + PUBLIC_PROVISIONER_URL, + ).toString(), + { + img: dataUrl, + type: "face", + }, + ); + await axios.patch( + new URL( + `/verification/${$verificaitonId}`, + PUBLIC_PROVISIONER_URL, + ).toString(), + ); + stopCamera(); + // Stay on this page and show spinner + // The verification step will be updated by the SSE response + // When status is set, showResults will be true + } catch (error) { + console.error("Failed to upload selfie:", error); + load = false; // Reset loading state on error + } } } } @@ -138,10 +144,22 @@ async function handleContinue() { if ($status === "duplicate") { // For duplicate case, skip provision and resolve the existing eVault URI - const existingW3id = $verificationWebsocketData?.w3id; + console.log("Websocket data:", $verificationWebsocketData); + console.log("Available keys:", Object.keys($verificationWebsocketData || {})); + + // Try different possible locations for w3id + const existingW3id = + $verificationWebsocketData?.w3id || + $verificationWebsocketData?.ename || + ($verificationWebsocketData as any)?.verification?.w3id || + ($verificationWebsocketData as any)?.verification?.ename; + if (!existingW3id) { + console.error("Full websocket data:", JSON.stringify($verificationWebsocketData, null, 2)); throw new Error("No w3id provided for duplicate eVault"); } + + console.log("Found w3id:", existingW3id); // Resolve the eVault URI from the registry const response = await axios.get( @@ -250,8 +268,8 @@ async function handleContinue() { Please make sure that your face is in the frame and clearly visible.
- {"Take Photo"}{load ? "Uploading..." : "Take Photo"} {:else if load && !showResults}
From 09aa7173401e819d99ca0ad257ceb307100218e7 Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Wed, 10 Dec 2025 01:37:52 +0530 Subject: [PATCH 21/21] fixed: claim flow --- .../src/routes/(auth)/verify/steps/selfie.svelte | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte index 8098a9fe6..e5d9a6419 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/verify/steps/selfie.svelte @@ -65,7 +65,6 @@ async function captureImage() { if (image === 1) { const context = canvas.getContext("2d"); if (context) { - load = true; // Show loading immediately try { context.drawImage(video, 0, 0, 1920, 1080); canvas.width = video.videoWidth; @@ -73,6 +72,7 @@ async function captureImage() { context.drawImage(video, 0, 0, canvas.width, canvas.height); const dataUrl = canvas.toDataURL("image/png"); Selfie.set(dataUrl); + load = true; // Show loading AFTER capturing image await axios.post( new URL( @@ -104,7 +104,8 @@ async function captureImage() { async function getApplicationPublicKey(): Promise { if (!globalState) throw new Error("Global state is not defined"); - const keyManager = globalState.keyService.getKeyManagerForContext("verification"); + const keyManager = await globalState.keyService.getKeyManager("verification"); + if (!keyManager) throw new Error("Key manager not found for verification context"); const publicKey = await keyManager.getPublicKey("default"); return publicKey; } @@ -268,8 +269,8 @@ async function handleContinue() { Please make sure that your face is in the frame and clearly visible.
- {load ? "Uploading..." : "Take Photo"}Take Photo {:else if load && !showResults}