2026-05-22 18:30:59 +02:00
{% extends "base.html" %}
{% block title %} — Step {{ step }}{% endblock %}
{% block stepper %}
< div class = "bg-slate-900/60 border-b border-slate-800" >
< div class = "max-w-6xl mx-auto px-4 py-3" >
< div class = "flex items-center gap-1 overflow-x-auto" >
{% set step_names = ["Auth", "Opret Bruger", "Tilslut Bank", "Konti", "Transaktioner", "Events"] %}
{% for i in range(1, 7) %}
< a href = "/demo/step/{{ i }}"
class="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm whitespace-nowrap transition
{% if i == step %}bg-violet-600 text-white font-semibold
{% elif i < step % } text-slate-300 hover:text-white
{% else %}text-slate-600 hover:text-slate-400{% endif %}">
< span class = "w-5 h-5 rounded-full text-xs font-bold flex items-center justify-center
{% if i < step % } bg-slate-700 text-slate-300
{% elif i == step %}bg-violet-500 text-white
{% else %}bg-slate-800 text-slate-600{% endif %}">{{ i }}< / span >
{{ step_names[i-1] }}
< / a >
{% if i < 6 % }
< span class = "text-slate-700" > › < / span >
{% endif %}
{% endfor %}
< / div >
< / div >
< / div >
{% endblock %}
{% block content %}
< div class = "grid grid-cols-1 lg:grid-cols-5 gap-6" >
<!-- Left: info panel -->
< div class = "lg:col-span-2 space-y-4" >
<!-- Step header -->
< div >
< div class = "flex items-center gap-2 mb-2" >
< span class = "w-8 h-8 rounded-full bg-violet-600 text-white text-sm font-bold flex items-center justify-center" > {{ step }}< / span >
< div >
< h2 class = "text-xl font-bold text-white" > {{ title }}< / h2 >
< p class = "text-slate-400 text-sm" > {{ subtitle }}< / p >
< / div >
< / div >
< / div >
<!-- Endpoint badge -->
< div class = "bg-slate-900 border border-slate-800 rounded-xl p-4" >
< div class = "flex items-center justify-between mb-2" >
< span class = "text-xs text-slate-500 uppercase tracking-wider" > Endpoint< / span >
< span class = "text-xs px-2 py-0 . 5 rounded-full font-mono font-semibold
{% if 'v2' in api_version %}bg-violet-900/50 text-violet-300 border border-violet-700/40
{% else %}bg-slate-800 text-slate-400{% endif %}">
{{ api_version }}
< / span >
< / div >
< code class = "text-sm text-emerald-400 font-mono break-all" > {{ endpoint }}< / code >
< / div >
<!-- Description -->
< div class = "bg-slate-900 border border-slate-800 rounded-xl p-4" >
2026-05-22 23:38:37 +02:00
< p class = "text-slate-300 text-sm leading-relaxed" > {{ description | safe }}< / p >
2026-05-22 18:30:59 +02:00
< / div >
<!-- curl example -->
< div class = "bg-slate-900 border border-slate-800 rounded-xl p-4" >
< div class = "flex items-center justify-between mb-3" >
< span class = "text-xs text-slate-500 uppercase tracking-wider" > cURL eksempel< / span >
< button onclick = "copyToClipboard('curl-{{ step }}')"
class="text-xs text-slate-400 hover:text-white transition px-2 py-1 rounded bg-slate-800 hover:bg-slate-700">
Kopier
< / button >
< / div >
< pre id = "curl-{{ step }}" class = "text-xs text-amber-300 font-mono whitespace-pre-wrap leading-relaxed" > {{ curl_example }}< / pre >
< / div >
<!-- Navigation -->
< div class = "flex gap-3" >
{% if prev_step %}
< a href = "/demo/step/{{ prev_step }}"
class="flex-1 text-center px-4 py-2.5 border border-slate-700 text-slate-300 hover:text-white hover:border-slate-500 rounded-xl text-sm transition">
← Step {{ prev_step }}
< / a >
{% endif %}
{% if next_step %}
< a href = "/demo/step/{{ next_step }}"
class="flex-1 text-center px-4 py-2.5 bg-violet-600 hover:bg-violet-500 text-white rounded-xl text-sm font-semibold transition">
Step {{ next_step }} →
< / a >
{% endif %}
< / div >
< / div >
<!-- Right: response panel -->
< div class = "lg:col-span-3 space-y-4" >
<!-- Tink Link special button (step 3) -->
{% if tink_link_url %}
{% if cb_success %}
<!-- Already connected — show success, hide connection UI -->
< div class = "bg-emerald-950/60 border border-emerald-700/50 rounded-xl p-5 flex items-start gap-4" >
< div class = "w-10 h-10 rounded-full bg-emerald-900/60 flex items-center justify-center flex-shrink-0" >
< svg class = "w-5 h-5 text-emerald-400" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M5 13l4 4L19 7" / > < / svg >
< / div >
< div class = "flex-1" >
< p class = "text-emerald-300 font-semibold text-base" > Bank forbundet!< / p >
< p class = "text-emerald-400/70 text-sm mt-0.5" > User token gemt i session. Trin 4– 6 er klar.< / p >
< a href = "/demo/reset"
class="inline-flex items-center gap-1.5 mt-3 text-xs text-slate-500 hover:text-slate-300 transition">
< svg class = "w-3 h-3" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" / > < / svg >
Start forfra
< / a >
< / div >
< / div >
{% else %}
<!-- Not yet connected — show connection UI -->
2026-05-22 19:04:06 +02:00
<!-- PRIMARY: direct callback flow -->
2026-05-22 18:30:59 +02:00
< div class = "bg-slate-900 border border-emerald-700/40 rounded-xl p-5 space-y-4" >
< div class = "flex items-start gap-3" >
< div class = "w-8 h-8 rounded-full bg-emerald-900/50 flex items-center justify-center flex-shrink-0" >
< svg class = "w-4 h-4 text-emerald-400" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" / > < / svg >
< / div >
< div >
< h3 class = "text-white font-semibold mb-1" > Tilslut testbank< / h3 >
2026-05-22 19:04:06 +02:00
< p class = "text-slate-400 text-sm" > Klik knappen, vælg Demo Bank og log ind — du redirectes automatisk tilbage.< / p >
2026-05-22 18:30:59 +02:00
< / div >
< / div >
<!-- Instructions -->
< div class = "bg-slate-800/60 border border-slate-700/50 rounded-lg p-4 text-sm space-y-2" >
< p class = "text-slate-300 font-semibold flex items-center gap-1.5" >
< svg class = "w-4 h-4 text-amber-400 flex-shrink-0" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" / > < / svg >
2026-05-22 19:04:06 +02:00
Trin i Tink Link
2026-05-22 18:30:59 +02:00
< / p >
< ol class = "text-slate-400 space-y-1.5 list-decimal list-inside leading-relaxed" >
2026-05-22 19:04:06 +02:00
< li > Vælg < span class = "text-slate-300 font-medium" > Tink Demo Bank< / span > < / li >
< li > Vælg < span class = "text-slate-300" > Open Banking< / span > → < span class = "text-slate-300" > Password And OTP< / span > < / li >
< li > Hent credentials: < span class = "font-mono text-amber-300 text-xs bg-slate-900 px-1.5 py-0.5 rounded" > Console → Demo Bank → Transactions → DK< / span > < / li >
< li > Indtast username + password → OTP vises på siden → Continue< / li >
< li > Vælg en konto → du redirectes automatisk tilbage her ✓< / li >
2026-05-22 18:30:59 +02:00
< / ol >
< / div >
2026-05-22 21:49:09 +02:00
<!-- Demo Bank credentials hint -->
< div class = "bg-slate-800/70 border border-amber-700/30 rounded-lg p-4" >
< div class = "flex items-center gap-2 mb-3" >
< svg class = "w-4 h-4 text-amber-400 flex-shrink-0" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" / > < / svg >
< span class = "text-amber-300 text-sm font-semibold" > Demo Bank Credentials< / span >
< / div >
< div class = "grid grid-cols-2 gap-2" >
< div >
< div class = "text-xs text-slate-500 mb-1" > Username< / div >
< div class = "flex items-center gap-2 bg-slate-900 border border-slate-700 rounded px-3 py-2" >
< code id = "demo-user" class = "text-sm font-mono text-emerald-300 flex-1" > u04877810< / code >
< button onclick = "copyText('demo-user', this)"
class="text-xs text-slate-500 hover:text-slate-300 transition flex-shrink-0">Kopier< / button >
< / div >
< / div >
< div >
< div class = "text-xs text-slate-500 mb-1" > Password< / div >
< div class = "flex items-center gap-2 bg-slate-900 border border-slate-700 rounded px-3 py-2" >
< code id = "demo-pass" class = "text-sm font-mono text-emerald-300 flex-1" > vxw774< / code >
< button onclick = "copyText('demo-pass', this)"
class="text-xs text-slate-500 hover:text-slate-300 transition flex-shrink-0">Kopier< / button >
< / div >
< / div >
< / div >
< p class = "text-xs text-slate-500 mt-2" > Vælg < span class = "text-slate-400" > Tink Demo Bank → Open Banking → Password And OTP< / span > < / p >
< / div >
2026-05-22 23:38:37 +02:00
< div class = "flex items-center gap-3 flex-wrap" >
2026-05-22 19:04:06 +02:00
< a href = "{{ tink_link_url }}"
2026-05-22 18:30:59 +02:00
class="inline-flex items-center gap-2 px-5 py-2.5 bg-emerald-600 hover:bg-emerald-500 text-white font-semibold rounded-lg transition">
Åbn Tink Link
2026-05-22 19:04:06 +02:00
< svg class = "w-4 h-4" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M14 5l7 7m0 0l-7 7m7-7H3" / > < / svg >
2026-05-22 18:30:59 +02:00
< / a >
2026-05-22 23:38:37 +02:00
{% if demo_bank_users %}
< button onclick = "document.getElementById('demo-users-modal').classList.remove('hidden')"
class="inline-flex items-center gap-1.5 px-4 py-2.5 border border-violet-700 text-violet-400 hover:text-violet-200 hover:border-violet-500 rounded-lg text-sm transition">
< svg class = "w-3.5 h-3.5" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" / > < / svg >
Vis testbrugere
< / button >
{% endif %}
2026-05-22 18:30:59 +02:00
< a href = "/demo/reset"
class="inline-flex items-center gap-1.5 px-4 py-2.5 border border-slate-700 text-slate-400 hover:text-white hover:border-slate-500 rounded-lg text-sm transition">
< svg class = "w-3.5 h-3.5" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" / > < / svg >
Start forfra
< / a >
< / div >
2026-05-22 23:38:37 +02:00
{% if demo_bank_users %}
<!-- Demo Bank users modal -->
< div id = "demo-users-modal" class = "hidden fixed inset-0 z-50 flex items-center justify-center p-4" >
< div class = "absolute inset-0 bg-black/70 backdrop-blur-sm" onclick = "document.getElementById('demo-users-modal').classList.add('hidden')" > < / div >
< div class = "relative bg-slate-900 border border-slate-700 rounded-2xl shadow-2xl w-full max-w-2xl overflow-hidden" >
< div class = "flex items-center justify-between px-6 py-4 border-b border-slate-800" >
< div >
< h3 class = "text-white font-semibold text-base" > Demo Bank — Testbrugere< / h3 >
< p class = "text-slate-500 text-xs mt-0.5" > Brug disse kredentialer når du logger ind i Tink Demo Bank. OTP er altid < code class = "text-violet-300" > 1234< / code > hvor det er påkrævet.< / p >
< / div >
< button onclick = "document.getElementById('demo-users-modal').classList.add('hidden')"
class="text-slate-500 hover:text-white transition p-1.5 rounded-lg hover:bg-slate-800">
< svg class = "w-5 h-5" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M6 18L18 6M6 6l12 12" / > < / svg >
< / button >
< / div >
< div class = "overflow-auto max-h-96" >
< table class = "w-full text-sm" >
< thead class = "bg-slate-800/50 sticky top-0" >
< tr class = "text-slate-400 text-xs uppercase tracking-wider" >
< th class = "px-4 py-2.5 text-left" > Market< / th >
< th class = "px-4 py-2.5 text-left" > Brugernavn< / th >
< th class = "px-4 py-2.5 text-left" > Password< / th >
< th class = "px-4 py-2.5 text-left" > OTP< / th >
< th class = "px-4 py-2.5 text-left" > Scenarie< / th >
< / tr >
< / thead >
< tbody class = "divide-y divide-slate-800" >
{% for u in demo_bank_users %}
< tr class = "hover:bg-slate-800/40 transition" >
< td class = "px-4 py-2.5 text-slate-300 font-medium" > {{ u.market }}< / td >
< td class = "px-4 py-2.5" >
< div class = "flex items-center gap-2" >
< code class = "font-mono text-emerald-300 text-xs" > {{ u.username }}< / code >
< button onclick = "navigator.clipboard.writeText('{{ u.username }}')" title = "Kopier"
class="text-slate-600 hover:text-slate-300 transition">
< svg class = "w-3 h-3" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" / > < / svg >
< / button >
< / div >
< / td >
< td class = "px-4 py-2.5" >
< div class = "flex items-center gap-2" >
< code class = "font-mono text-violet-300 text-xs" > {{ u.password }}< / code >
< button onclick = "navigator.clipboard.writeText('{{ u.password }}')" title = "Kopier"
class="text-slate-600 hover:text-slate-300 transition">
< svg class = "w-3 h-3" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" / > < / svg >
< / button >
< / div >
< / td >
< td class = "px-4 py-2.5 font-mono text-xs text-slate-400" > {{ u.otp or "—" }}< / td >
< td class = "px-4 py-2.5" >
< span class = "px-2 py-0.5 rounded-full text-xs font-medium {% if 'fejl' in u.scenario.lower() %}bg-red-900/40 text-red-400{% else %}bg-emerald-900/40 text-emerald-400{% endif %}" >
{{ u.scenario }}
< / span >
< / td >
< / tr >
{% endfor %}
< / tbody >
< / table >
< / div >
< div class = "px-6 py-3 border-t border-slate-800 text-xs text-slate-500" >
Kilde: < a href = "https://docs.tink.com/resources/tutorials/test-your-integration-with-demo-bank" target = "_blank" class = "text-violet-400 hover:text-violet-300 underline" > Tink Demo Bank dokumentation< / a >
< / div >
< / div >
< / div >
{% endif %}
2026-05-22 18:30:59 +02:00
< / div >
2026-05-22 19:04:06 +02:00
<!-- FALLBACK: console.tink.com/callback + manual code paste -->
2026-05-22 18:30:59 +02:00
< details class = "bg-slate-900 border border-slate-700/30 rounded-xl overflow-hidden" >
< summary class = "px-5 py-3 cursor-pointer text-slate-500 hover:text-slate-400 text-xs flex items-center gap-2 select-none" >
< svg class = "w-3.5 h-3.5" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" / > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M15 12a3 3 0 11-6 0 3 3 0 016 0z" / > < / svg >
2026-05-22 19:04:06 +02:00
Alternativ: manuel kode-indsætning via console.tink.com
2026-05-22 18:30:59 +02:00
< span class = "ml-auto" > ▾< / span >
< / summary >
2026-05-22 19:04:06 +02:00
< div class = "px-5 pb-4 pt-3 border-t border-slate-800 space-y-3" >
< a href = "{{ dev_tink_link_url }}" target = "_blank"
2026-05-22 18:30:59 +02:00
class="inline-flex items-center gap-2 px-4 py-2 bg-slate-700 hover:bg-slate-600 text-slate-300 text-sm rounded-lg transition">
2026-05-22 19:04:06 +02:00
Åbn med console callback
2026-05-22 18:30:59 +02:00
< svg class = "w-3.5 h-3.5" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" / > < / svg >
< / a >
2026-05-22 19:04:06 +02:00
< form method = "POST" action = "/demo/step/3" class = "flex gap-2 items-stretch" >
< input type = "text" name = "code" placeholder = "Indsæt code=XXXX fra console.tink.com/callback..."
class="flex-1 bg-slate-800 border border-slate-700 text-slate-200 rounded-lg px-3 py-2 text-sm font-mono placeholder-slate-600 focus:outline-none focus:border-emerald-600" required>
< button type = "submit"
class="px-4 py-2 bg-emerald-700 hover:bg-emerald-600 text-white text-sm font-semibold rounded-lg transition whitespace-nowrap">
Brug kode
< / button >
< / form >
2026-05-22 18:30:59 +02:00
< / div >
< / details >
{% endif %}{# end not cb_success #}
{% endif %}{# end tink_link_url #}
<!-- Error state -->
{% if error %}
< div class = "bg-red-950/50 border border-red-800/50 rounded-xl p-5" >
< div class = "flex items-start gap-3" >
< span class = "text-red-400 text-xl flex-shrink-0" > ✕< / span >
< div >
< h3 class = "text-red-300 font-semibold mb-1" > Fejl< / h3 >
< pre class = "text-red-400 text-sm font-mono whitespace-pre-wrap" > {{ error }}< / pre >
< / div >
< / div >
< / div >
{% endif %}
<!-- JSON response -->
{% if result %}
< div class = "bg-slate-900 border border-slate-800 rounded-xl overflow-hidden" >
< div class = "flex items-center justify-between px-4 py-3 border-b border-slate-800" >
< div class = "flex items-center gap-2" >
< span class = "w-2 h-2 rounded-full bg-emerald-400" > < / span >
< span class = "text-sm text-slate-300 font-semibold" > Response< / span >
< span class = "text-xs text-emerald-400 font-mono" > 200 OK< / span >
{% if is_demo %}
< span class = "text-xs px-2 py-0.5 rounded-full font-semibold bg-amber-900/60 text-amber-300 border border-amber-700/40" > ⚠ Sample Data< / span >
{% endif %}
< / div >
< button onclick = "copyToClipboard('json-{{ step }}')"
class="text-xs text-slate-400 hover:text-white transition px-2 py-1 rounded bg-slate-800 hover:bg-slate-700">
Kopier JSON
< / button >
< / div >
< div class = "p-4 max-h-[520px] overflow-y-auto" >
< pre id = "json-{{ step }}" class = "raw-json" > {{ result | tojson(indent=2) }}< / pre >
< / div >
< / div >
{% elif not error %}
<!-- Waiting state -->
< div class = "bg-slate-900 border border-slate-800 rounded-xl p-10 flex flex-col items-center justify-center gap-3 text-center" >
< div class = "w-12 h-12 rounded-full bg-slate-800 flex items-center justify-center" >
< svg class = "w-6 h-6 text-slate-500" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke-linecap = "round" stroke-linejoin = "round" stroke-width = "2" d = "M13 10V3L4 14h7v7l9-11h-7z" / > < / svg >
< / div >
< p class = "text-slate-400 text-sm" > Klik på knappen ovenfor for at køre dette API-kald og se svaret her.< / p >
< / div >
{% endif %}
< / div >
< / div >
{% endblock %}