Files
boc/quixzoom-sso-auth/mina-sidor.html
T
Bernt 48ea61cdcc docs: add quixzoom-auth-core product to AAMOS
- Product documentation in docs/products/
- Updated MEMORY.md with product info
- quiXzoom Auth Core as AAMOS Identity product
2026-07-14 09:58:53 +00:00

329 lines
15 KiB
HTML

<!DOCTYPE html>
<html lang="sv">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mina Sidor — quiXzoom</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<style>
:root{
--bg:#F7F7F5;
--white:#FFFFFF;
--blue:#0066FF;
--blue-dark:#0052CC;
--green:#00C853;
--text:#1a1a1a;
--text-body:#3a3a3a;
--text-muted:#6B6B6B;
--radius:16px;
--shadow:0 4px 24px rgba(0,0,0,.08);
}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,BlinkMacSystemFont,'Inter','Helvetica Neue',sans-serif;background:var(--bg);color:var(--text-body);min-height:100vh}
/* Header */
.header{background:var(--white);border-bottom:1px solid rgba(0,0,0,.06);padding:16px 24px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100}
.logo{display:flex;align-items:center;gap:12px;text-decoration:none}
.logo-icon{width:36px;height:36px;background:var(--blue);border-radius:10px;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;font-size:18px}
.logo-text{font-size:20px;font-weight:700;color:var(--text);letter-spacing:-.5px}
.logo-text span{color:var(--blue)}
.nav{display:flex;gap:8px;align-items:center}
.nav-link{padding:8px 16px;border-radius:8px;color:var(--text-body);text-decoration:none;font-size:14px;font-weight:500;transition:.2s}
.nav-link:hover{background:rgba(0,102,255,.06);color:var(--blue)}
.nav-link.active{background:var(--blue);color:#fff}
.user-menu{display:flex;align-items:center;gap:12px}
.user-avatar{width:36px;height:36px;border-radius:50%;background:var(--blue);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:14px}
.user-name{font-size:14px;font-weight:600;color:var(--text)}
.logout-btn{padding:8px 16px;border:1px solid rgba(0,0,0,.1);border-radius:8px;background:transparent;color:var(--text-muted);font-size:13px;cursor:pointer;transition:.2s}
.logout-btn:hover{border-color:#ff4444;color:#ff4444}
/* Main */
.main{max-width:1200px;margin:0 auto;padding:32px 24px}
/* Dashboard Grid */
.dashboard{display:grid;grid-template-columns:280px 1fr;gap:24px}
/* Sidebar */
.sidebar{background:var(--white);border-radius:var(--radius);padding:20px;box-shadow:var(--shadow)}
.sidebar-menu{display:flex;flex-direction:column;gap:4px}
.sidebar-item{padding:12px 16px;border-radius:10px;color:var(--text-body);text-decoration:none;font-size:14px;font-weight:500;display:flex;align-items:center;gap:12px;transition:.2s;cursor:pointer;border:none;background:transparent;width:100%;text-align:left}
.sidebar-item:hover{background:rgba(0,102,255,.06);color:var(--blue)}
.sidebar-item.active{background:var(--blue);color:#fff}
.sidebar-icon{width:20px;height:20px;display:flex;align-items:center;justify-content:center}
.sidebar-divider{height:1px;background:rgba(0,0,0,.06);margin:12px 0}
/* Content */
.content{display:flex;flex-direction:column;gap:24px}
/* Stats Cards */
.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
.stat-card{background:var(--white);border-radius:var(--radius);padding:24px;box-shadow:var(--shadow)}
.stat-label{font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--text-muted);margin-bottom:8px}
.stat-value{font-size:32px;font-weight:700;color:var(--text);letter-spacing:-1px}
.stat-change{font-size:13px;color:var(--green);margin-top:4px;font-weight:500}
.stat-change.negative{color:#ff4444}
/* Wallet Card */
.wallet-card{background:linear-gradient(135deg,var(--blue),var(--blue-dark));border-radius:var(--radius);padding:28px;color:#fff;position:relative;overflow:hidden}
.wallet-card::before{content:'';position:absolute;top:-50%;right:-20%;width:300px;height:300px;background:rgba(255,255,255,.05);border-radius:50%}
.wallet-label{font-size:12px;text-transform:uppercase;letter-spacing:1px;opacity:.8;margin-bottom:8px}
.wallet-balance{font-size:42px;font-weight:700;letter-spacing:-1px}
.wallet-currency{font-size:18px;opacity:.8;margin-left:4px}
.wallet-actions{display:flex;gap:12px;margin-top:20px}
.wallet-btn{padding:10px 20px;border-radius:8px;background:rgba(255,255,255,.15);color:#fff;border:none;font-size:14px;font-weight:500;cursor:pointer;transition:.2s}
.wallet-btn:hover{background:rgba(255,255,255,.25)}
.wallet-btn.primary{background:#fff;color:var(--blue)}
/* Missions */
.section{background:var(--white);border-radius:var(--radius);padding:24px;box-shadow:var(--shadow)}
.section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px}
.section-title{font-size:18px;font-weight:700;color:var(--text)}
.section-action{color:var(--blue);text-decoration:none;font-size:14px;font-weight:500}
.mission-list{display:flex;flex-direction:column;gap:12px}
.mission-item{display:flex;align-items:center;gap:16px;padding:16px;border-radius:12px;background:var(--bg);transition:.2s}
.mission-item:hover{box-shadow:0 2px 8px rgba(0,0,0,.06)}
.mission-icon{width:48px;height:48px;border-radius:12px;background:rgba(0,102,255,.1);display:flex;align-items:center;justify-content:center;color:var(--blue);font-size:20px}
.mission-info{flex:1}
.mission-title{font-size:15px;font-weight:600;color:var(--text);margin-bottom:4px}
.mission-meta{font-size:13px;color:var(--text-muted)}
.mission-reward{font-size:16px;font-weight:700;color:var(--green)}
.mission-status{padding:6px 12px;border-radius:6px;font-size:12px;font-weight:600}
.mission-status.pending{background:rgba(255,193,7,.15);color:#f9a825}
.mission-status.approved{background:rgba(0,200,83,.15);color:var(--green)}
.mission-status.rejected{background:rgba(255,68,68,.15);color:#ff4444}
/* Login State */
.login-prompt{text-align:center;padding:80px 24px}
.login-prompt h1{font-size:32px;font-weight:700;color:var(--text);margin-bottom:16px}
.login-prompt p{font-size:16px;color:var(--text-muted);margin-bottom:32px;max-width:400px;margin-left:auto;margin-right:auto}
.login-btn{padding:14px 32px;border-radius:12px;background:var(--blue);color:#fff;border:none;font-size:16px;font-weight:600;cursor:pointer;transition:.2s;text-decoration:none;display:inline-block}
.login-btn:hover{background:var(--blue-dark);transform:translateY(-1px)}
/* Loading */
.loading{display:flex;align-items:center;justify-content:center;min-height:60vh}
.loading-spinner{width:40px;height:40px;border:3px solid rgba(0,102,255,.1);border-top-color:var(--blue);border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
/* Mobile */
@media(max-width:768px){
.dashboard{grid-template-columns:1fr}
.stats{grid-template-columns:1fr}
.header{padding:12px 16px}
.nav{display:none}
.main{padding:16px}
}
</style>
</head>
<body>
<!-- Header -->
<header class="header">
<a href="/" class="logo">
<div class="logo-icon">Q</div>
<div class="logo-text">qui<span>X</span>zoom</div>
</a>
<nav class="nav">
<a href="/" class="nav-link">Hem</a>
<a href="/missions" class="nav-link">Uppdrag</a>
<a href="/mina-sidor" class="nav-link active">Mina Sidor</a>
<a href="/help" class="nav-link">Hjälp</a>
</nav>
<div class="user-menu" id="userMenu" style="display:none">
<div class="user-avatar" id="userAvatar">Z</div>
<span class="user-name" id="userName">Zoomer</span>
<button class="logout-btn" onclick="logout()">Logga ut</button>
</div>
</header>
<!-- Main Content -->
<main class="main">
<!-- Loading State -->
<div class="loading" id="loadingState">
<div class="loading-spinner"></div>
</div>
<!-- Login Prompt (shown if not authenticated) -->
<div class="login-prompt" id="loginPrompt" style="display:none">
<h1>Välkommen till quiXzoom</h1>
<p>Logga in för att se dina uppdrag, saldo och inställningar. Samma konto fungerar i appen och på webben.</p>
<a href="https://auth.quixzoom.com/login?redirect=https://www.quixzoom.com/mina-sidor" class="login-btn">Logga in</a>
<p style="margin-top:24px;font-size:14px">
Har du inget konto? <a href="https://auth.quixzoom.com/register" style="color:var(--blue);text-decoration:none;font-weight:600">Registrera dig</a>
</p>
</div>
<!-- Dashboard (shown if authenticated) -->
<div class="dashboard" id="dashboard" style="display:none">
<!-- Sidebar -->
<aside class="sidebar">
<nav class="sidebar-menu">
<button class="sidebar-item active" onclick="showSection('overview')">
<span class="sidebar-icon">📊</span>
Översikt
</button>
<button class="sidebar-item" onclick="showSection('missions')">
<span class="sidebar-icon">📍</span>
Mina Uppdrag
</button>
<button class="sidebar-item" onclick="showSection('wallet')">
<span class="sidebar-icon">💰</span>
Plånbok
</button>
<button class="sidebar-item" onclick="showSection('profile')">
<span class="sidebar-icon">👤</span>
Profil
</button>
<div class="sidebar-divider"></div>
<button class="sidebar-item" onclick="showSection('settings')">
<span class="sidebar-icon">⚙️</span>
Inställningar
</button>
</nav>
</aside>
<!-- Content -->
<div class="content">
<!-- Wallet Card -->
<div class="wallet-card">
<div class="wallet-label">Tillgängligt Saldo</div>
<div class="wallet-balance">
<span id="walletBalance">0.00</span>
<span class="wallet-currency">USD</span>
</div>
<div style="margin-top:4px;opacity:.7;font-size:14px">
<span id="tokenBalance">0</span> QZ Tokens
</div>
<div class="wallet-actions">
<button class="wallet-btn primary">Begär utbetalning</button>
<button class="wallet-btn">Transaktionshistorik</button>
</div>
</div>
<!-- Stats -->
<div class="stats">
<div class="stat-card">
<div class="stat-label">Genomförda Uppdrag</div>
<div class="stat-value" id="completedMissions">0</div>
<div class="stat-change">+12 denna vecka</div>
</div>
<div class="stat-card">
<div class="stat-label">Godkännandegrad</div>
<div class="stat-value" id="approvalRate">0%</div>
<div class="stat-change">+2.3% denna månad</div>
</div>
<div class="stat-card">
<div class="stat-label">Veckans Intjäning</div>
<div class="stat-value" id="weeklyEarnings">$0</div>
<div class="stat-change">+$45 vs förra veckan</div>
</div>
</div>
<!-- Recent Missions -->
<div class="section">
<div class="section-header">
<h2 class="section-title">Senaste Uppdrag</h2>
<a href="/missions" class="section-action">Se alla →</a>
</div>
<div class="mission-list" id="missionList">
<!-- Populated by JS -->
</div>
</div>
</div>
</div>
</main>
<script type="module">
import { quixzoomAuth } from './sso-client.js';
// DOM elements
const loadingState = document.getElementById('loadingState');
const loginPrompt = document.getElementById('loginPrompt');
const dashboard = document.getElementById('dashboard');
const userMenu = document.getElementById('userMenu');
const userAvatar = document.getElementById('userAvatar');
const userName = document.getElementById('userName');
// Initialize
async function init() {
const user = await quixzoomAuth.init();
loadingState.style.display = 'none';
if (user) {
showDashboard(user);
} else {
showLoginPrompt();
}
}
function showDashboard(user) {
dashboard.style.display = 'grid';
userMenu.style.display = 'flex';
// Update user info
userAvatar.textContent = (user.first_name?.[0] || 'Z').toUpperCase();
userName.textContent = `${user.first_name || ''} ${user.last_name || ''}`.trim() || 'Zoomer';
// Load dashboard data
loadDashboardData();
}
function showLoginPrompt() {
loginPrompt.style.display = 'block';
}
async function loadDashboardData() {
// Mock data - replace with API calls
document.getElementById('walletBalance').textContent = '1,247.50';
document.getElementById('tokenBalance').textContent = '1,247.5';
document.getElementById('completedMissions').textContent = '47';
document.getElementById('approvalRate').textContent = '94%';
document.getElementById('weeklyEarnings').textContent = '$312';
// Mock missions
const missions = [
{title: 'Fasadinspektion — Stureplan 4', location: 'Stockholm', reward: 85, status: 'approved', date: 'Idag'},
{title: 'Vägskade dokumentation', location: 'Södermalm', reward: 45, status: 'pending', date: 'Igår'},
{title: 'Butiksfasad — Kungsgatan', location: 'Stockholm', reward: 60, status: 'approved', date: '2 dagar sedan'},
];
const missionList = document.getElementById('missionList');
missionList.innerHTML = missions.map(m => `
<div class="mission-item">
<div class="mission-icon">📸</div>
<div class="mission-info">
<div class="mission-title">${m.title}</div>
<div class="mission-meta">${m.location}${m.date}</div>
</div>
<div class="mission-reward">$${m.reward}</div>
<div class="mission-status ${m.status}">${m.status === 'approved' ? 'Godkänd' : m.status === 'pending' ? 'Granskas' : 'Avvisad'}</div>
</div>
`).join('');
}
// Global functions for onclick handlers
window.logout = async () => {
await quixzoomAuth.logout();
window.location.reload();
};
window.showSection = (section) => {
// Update active sidebar item
document.querySelectorAll('.sidebar-item').forEach(item => {
item.classList.remove('active');
});
event.target.closest('.sidebar-item').classList.add('active');
// TODO: Show different content sections
console.log('Show section:', section);
};
// Start
init();
</script>
</body>
</html>