Files
boc/quixzoom-landing-fixed/zoomer-profile.html
T

954 lines
37 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="sv" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<title>Profil — quiXzoom</title>
<link rel="stylesheet" >
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--font-text);
background: var(--grouped-background-primary);
color: var(--label-primary);
min-height: 100dvh;
padding-top: env(safe-area-inset-top, 44px);
padding-bottom: calc(env(safe-area-inset-bottom, 34px) + 83px);
-webkit-font-smoothing: antialiased;
}
/* Nav */
.nav-bar {
position: sticky; top: 0; z-index: 200;
display: flex; align-items: center; justify-content: center;
height: 44px; padding: 0 16px;
background: var(--navbar-bg);
backdrop-filter: saturate(180%) blur(20px);
-webkit-backdrop-filter: saturate(180%) blur(20px);
border-bottom: 0.5px solid var(--separator);
}
.nav-title { font-size: 17px; font-weight: 600; letter-spacing: -0.41px; }
/* Profile Hero */
.profile-hero {
display: flex; flex-direction: column; align-items: center;
padding: 32px 20px 24px;
}
.avatar {
width: 88px; height: 88px; border-radius: 50%;
background: linear-gradient(135deg, var(--ios-blue), var(--ios-indigo));
display: flex; align-items: center; justify-content: center;
font-size: 42px; margin-bottom: 14px;
position: relative;
}
.avatar-badge {
position: absolute; bottom: 0; right: 0;
width: 26px; height: 26px; border-radius: 50%;
border: 2.5px solid var(--grouped-background-primary);
display: flex; align-items: center; justify-content: center;
font-size: 14px;
}
.avatar-badge.verified { background: var(--ios-green); }
.avatar-badge.unverified { background: var(--ios-orange); }
.profile-name {
font-family: var(--font-display);
font-size: 24px; font-weight: 700; letter-spacing: -0.5px;
margin-bottom: 4px;
}
.profile-id {
font-size: 13px; color: var(--label-secondary);
font-family: var(--font-mono);
}
.rating-row {
display: flex; align-items: center; gap: 6px;
margin-top: 10px;
}
.stars { color: var(--ios-yellow); font-size: 16px; }
.rating-num { font-size: 15px; font-weight: 600; }
.rating-count { font-size: 13px; color: var(--label-secondary); }
/* Stats */
.stats-grid {
display: grid; grid-template-columns: 1fr 1fr 1fr;
margin: 0 16px 20px;
background: var(--background-secondary);
border-radius: 14px;
border: 0.5px solid var(--separator);
overflow: hidden;
}
.stat-cell {
padding: 16px 8px; text-align: center;
border-right: 0.5px solid var(--separator);
}
.stat-cell:last-child { border-right: none; }
.stat-val { font-size: 22px; font-weight: 700; font-family: var(--font-display); }
.stat-lbl { font-size: 11px; color: var(--label-secondary); margin-top: 2px; }
.green { color: var(--ios-green); }
.blue { color: var(--ios-blue); }
.yellow { color: var(--ios-yellow); }
/* Section */
.section { margin: 0 16px 20px; }
.section-header {
font-size: 13px; font-weight: 500; color: var(--label-secondary);
text-transform: uppercase; letter-spacing: 0.5px;
padding: 0 4px 8px;
}
.section-card {
background: var(--background-secondary);
border-radius: 14px; overflow: hidden;
border: 0.5px solid var(--separator);
}
/* List row */
.list-row {
display: flex; align-items: center; gap: 14px;
padding: 13px 16px;
border-bottom: 0.5px solid var(--separator);
cursor: pointer; transition: opacity 0.12s;
}
.list-row:last-child { border-bottom: none; }
.list-row:active { opacity: 0.7; }
.row-icon-wrap {
width: 32px; height: 32px; border-radius: 8px;
display: flex; align-items: center; justify-content: center;
font-size: 18px; flex-shrink: 0;
}
.row-body { flex: 1; }
.row-title { font-size: 16px; }
.row-sub { font-size: 13px; color: var(--label-secondary); margin-top: 2px; }
.row-right {
display: flex; align-items: center; gap: 6px;
color: var(--label-tertiary); font-size: 15px;
}
.chevron { font-size: 15px; color: var(--label-tertiary); }
/* KYC Card */
.kyc-card {
background: var(--background-secondary);
border-radius: 14px; overflow: hidden;
border: 0.5px solid var(--separator);
}
.kyc-top {
display: flex; gap: 14px; align-items: center;
padding: 16px;
}
.kyc-icon {
width: 52px; height: 52px; border-radius: 12px;
display: flex; align-items: center; justify-content: center;
font-size: 26px; flex-shrink: 0;
}
.kyc-icon.unverified { background: rgba(255,149,0,0.15); }
.kyc-icon.verified { background: rgba(52,199,89,0.15); }
.kyc-icon.pending { background: rgba(0,122,255,0.15); }
.kyc-info { flex: 1; }
.kyc-title { font-size: 17px; font-weight: 600; margin-bottom: 3px; }
.kyc-desc { font-size: 13px; color: var(--label-secondary); }
.kyc-status-bar {
padding: 10px 16px;
font-size: 13px;
border-top: 0.5px solid var(--separator);
display: flex; align-items: center; gap: 8px;
}
.status-chip {
display: inline-flex; align-items: center; gap: 4px;
padding: 4px 10px; border-radius: 20px;
font-size: 12px; font-weight: 600;
}
.chip-unverified { background: rgba(255,149,0,0.15); color: var(--ios-orange); }
.chip-verified { background: rgba(52,199,89,0.15); color: var(--ios-green); }
.chip-pending { background: rgba(0,122,255,0.15); color: var(--ios-blue); }
.kyc-btn {
display: block; width: 100%;
padding: 15px;
border: none; border-radius: 0;
font-family: var(--font-text); font-size: 16px; font-weight: 700;
cursor: pointer; transition: opacity 0.15s;
border-top: 0.5px solid var(--separator);
letter-spacing: -0.2px;
}
.kyc-btn.unverified { background: var(--ios-orange); color: #fff; }
.kyc-btn.verified { background: var(--fill-secondary); color: var(--label-secondary); pointer-events: none; }
.kyc-btn.pending { background: var(--fill-secondary); color: var(--ios-blue); pointer-events: none; }
.kyc-btn:active { opacity: 0.8; }
/* Mission type breakdown */
.type-row {
display: flex; align-items: center; gap: 10px;
padding: 11px 16px;
border-bottom: 0.5px solid var(--separator);
}
.type-row:last-child { border-bottom: none; }
.type-icon { font-size: 16px; width: 24px; text-align: center; }
.type-label { flex: 1; font-size: 14px; }
.type-count { font-size: 14px; font-weight: 600; color: var(--label-secondary); }
.type-bar-wrap { width: 80px; }
.type-bar { height: 4px; border-radius: 2px; background: var(--ios-blue); }
/* Onboarding Progress Bar */
.onboarding-card {
margin: 0 16px 20px;
background: var(--background-secondary);
border-radius: 16px; overflow: hidden;
border: 0.5px solid var(--separator);
}
.onboarding-header {
display: flex; justify-content: space-between; align-items: center;
padding: 14px 16px 10px;
}
.onboarding-title { font-size: 16px; font-weight: 600; }
.onboarding-fraction { font-size: 13px; color: var(--label-secondary); font-weight: 500; }
.onboarding-track {
height: 5px; background: var(--fill-secondary);
margin: 0 16px 14px; border-radius: 3px; overflow: hidden;
}
.onboarding-fill {
height: 100%; border-radius: 3px;
background: linear-gradient(90deg, var(--ios-blue), var(--ios-indigo));
transition: width 0.6s cubic-bezier(0.34,1.56,0.64,1);
}
.onboarding-steps {
display: flex; border-top: 0.5px solid var(--separator);
}
.onboarding-step {
flex: 1; padding: 13px 8px; text-align: center;
border-right: 0.5px solid var(--separator);
}
.onboarding-step:last-child { border-right: none; }
.os-icon { font-size: 22px; margin-bottom: 5px; }
.os-label { font-size: 11px; font-weight: 500; color: var(--label-secondary); }
.os-label.done { color: var(--ios-green); }
.os-label.active { color: var(--ios-blue); }
.onboarding-cta {
display: block; width: calc(100% - 32px);
margin: 0 16px 16px;
padding: 15px;
background: var(--ios-blue); color: #fff;
border: none; border-radius: 12px;
font-family: var(--font-text); font-size: 16px; font-weight: 700;
cursor: pointer; transition: opacity 0.15s;
letter-spacing: -0.2px; text-align: center;
}
.onboarding-cta:active { opacity: 0.8; }
.onboarding-cta:disabled { background: var(--fill-secondary); color: var(--label-secondary); pointer-events: none; }
/* Earnings Calculator */
.calc-card {
background: var(--background-secondary);
border-radius: 16px; overflow: hidden;
border: 0.5px solid var(--separator);
}
.calc-header { padding: 14px 16px 12px; border-bottom: 0.5px solid var(--separator); }
.calc-title { font-size: 16px; font-weight: 600; }
.calc-sub { font-size: 13px; color: var(--label-secondary); margin-top: 2px; }
.calc-body { padding: 16px; }
.calc-slider-row {
display: flex; justify-content: space-between; align-items: center;
margin-bottom: 6px;
}
.calc-label { font-size: 14px; color: var(--label-secondary); }
.calc-value { font-size: 14px; font-weight: 600; }
.calc-slider {
width: 100%; margin-bottom: 16px;
-webkit-appearance: none; appearance: none;
height: 4px; border-radius: 2px;
background: var(--ios-blue); outline: none;
}
.calc-slider::-webkit-slider-thumb {
-webkit-appearance: none; appearance: none;
width: 22px; height: 22px; border-radius: 50%;
background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.25);
cursor: pointer;
}
.calc-result {
background: rgba(48,209,88,0.08);
border: 0.5px solid rgba(48,209,88,0.2);
border-radius: 12px; padding: 16px; text-align: center;
}
.calc-result-label { font-size: 13px; color: var(--label-secondary); margin-bottom: 6px; }
.calc-result-amount {
font-family: var(--font-display);
font-size: 36px; font-weight: 800; letter-spacing: -1px;
color: var(--ios-green);
}
.calc-result-unit { font-size: 13px; color: var(--label-secondary); margin-top: 4px; }
.calc-breakdown {
display: flex; justify-content: space-between;
margin-top: 12px; padding-top: 12px;
border-top: 0.5px solid var(--separator);
}
.calc-breakdown-item { text-align: center; }
.calc-breakdown-num { font-size: 16px; font-weight: 700; }
.calc-breakdown-label { font-size: 11px; color: var(--label-secondary); margin-top: 2px; }
/* Referral Program */
.referral-card {
background: linear-gradient(135deg, rgba(10,132,255,0.08), rgba(94,92,230,0.08));
border: 0.5px solid rgba(10,132,255,0.2);
border-radius: 16px; padding: 20px;
}
.referral-header {
display: flex; gap: 12px; align-items: center; margin-bottom: 14px;
}
.referral-icon {
width: 48px; height: 48px; border-radius: 12px;
background: rgba(10,132,255,0.15);
display: flex; align-items: center; justify-content: center;
font-size: 24px;
}
.referral-info {}
.referral-title { font-size: 17px; font-weight: 700; }
.referral-desc { font-size: 13px; color: var(--label-secondary); margin-top: 3px; }
.referral-code-row {
display: flex; gap: 10px; align-items: stretch; margin-bottom: 14px;
}
.referral-code {
flex: 1; background: var(--fill-secondary); border-radius: 10px;
padding: 12px 14px;
font-family: var(--font-mono); font-size: 16px; font-weight: 700;
letter-spacing: 2px; color: var(--ios-blue); text-align: center;
}
.referral-copy-btn {
background: var(--ios-blue); color: #fff;
border: none; border-radius: 10px;
padding: 12px 16px; font-size: 14px; font-weight: 700;
cursor: pointer; transition: opacity 0.15s;
}
.referral-copy-btn:active { opacity: 0.8; }
.referral-share-btn {
display: block; width: 100%;
padding: 13px; background: rgba(10,132,255,0.12); color: var(--ios-blue);
border: 0.5px solid rgba(10,132,255,0.2); border-radius: 10px;
font-size: 15px; font-weight: 600;
cursor: pointer; transition: opacity 0.15s; text-align: center;
margin-bottom: 12px;
}
.referral-share-btn:active { opacity: 0.7; }
.referral-stats {
display: flex; gap: 10px;
}
.referral-stat {
flex: 1; background: var(--fill-secondary); border-radius: 10px;
padding: 10px; text-align: center;
}
.referral-stat-num { font-size: 20px; font-weight: 700; font-family: var(--font-display); }
.referral-stat-label { font-size: 11px; color: var(--label-secondary); margin-top: 2px; }
/* Loader */
@keyframes spin { to { transform: rotate(360deg); } }
.spinner { width:24px; height:24px; border-radius:50%; border:3px solid var(--fill-secondary); border-top-color:var(--ios-blue); animation:spin 0.8s linear infinite; display:inline-block; }
/* Tab Bar */
.tab-bar {
position: fixed; bottom: 0; left: 0; right: 0; z-index: 300;
height: calc(49px + env(safe-area-inset-bottom, 34px));
background: var(--tabbar-bg);
backdrop-filter: saturate(180%) blur(20px);
-webkit-backdrop-filter: saturate(180%) blur(20px);
border-top: 0.5px solid var(--separator);
display: flex; align-items: flex-start; padding-top: 8px;
}
.tab-item { flex:1; display:flex; flex-direction:column; align-items:center; gap:3px; cursor:pointer; text-decoration:none; padding:0 4px; }
.tab-icon { font-size:24px; line-height:1; }
.tab-label { font-size:10px; font-weight:500; color:var(--label-tertiary); }
.tab-item.active .tab-label { color:var(--ios-blue); }
/* Toast */
.toast { position:fixed; bottom:calc(env(safe-area-inset-bottom,34px)+100px); left:50%; transform:translateX(-50%) translateY(20px); background:var(--background-secondary); border:0.5px solid var(--separator); border-radius:20px; padding:10px 18px; font-size:14px; font-weight:500; box-shadow:0 8px 32px rgba(0,0,0,0.3); opacity:0; transition:all 0.3s; z-index:9999; white-space:nowrap; }
.toast.show { opacity:1; transform:translateX(-50%) translateY(0); }
@media (max-width: 640px) {
.hero h1 { font-size: 2rem !important; }
.hero p { font-size: 1rem !important; }
.card { padding: 1.5rem !important; }
.grid { grid-template-columns: 1fr !important; }
.btn { padding: 0.75rem 1.5rem !important; font-size: 1rem !important; }
}
</style>
<style id="wcag-contrast-enforcement">
/* AAMOS GLOBAL CONTRAST ENFORCEMENT — WCAG AA (4.5:1 minimum) */
/* Regel: Ingen text under 70% opacity. Aldrig. */
body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
/* Fix common low-contrast patterns */
[style*="rgba(60,60,67,0.4)"] { color: rgba(60,60,67,0.65) !important; }
[style*="rgba(60,60,67,0.3)"] { color: rgba(60,60,67,0.65) !important; }
[style*="rgba(255,255,255,0.4)"] { color: rgba(255,255,255,0.72) !important; }
[style*="rgba(255,255,255,0.3)"] { color: rgba(255,255,255,0.72) !important; }
[style*="opacity: 0.4"] { opacity: 0.72 !important; }
[style*="opacity: 0.3"] { opacity: 0.72 !important; }
@media (max-width: 640px) {
.hero h1 { font-size: 2rem !important; }
.hero p { font-size: 1rem !important; }
.card { padding: 1.5rem !important; }
.grid { grid-template-columns: 1fr !important; }
.btn { padding: 0.75rem 1.5rem !important; font-size: 1rem !important; }
}
</style>
<script src="i18n.js"></script>
<meta property="og:type" content="website">
<meta property="og:title" content="Profil — quiXzoom">
<meta property="og:description" content="quiXzoom — Earn per Mission. No Platform Fee.">
<meta property="og:url" content="https://www.quixzoom.com/zoomer-profile.html">
<meta property="og:image" content="https://www.quixzoom.com/images/zoomer-earnings.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="quiXzoom Zoomer profile and weekly earnings">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://www.quixzoom.com/images/zoomer-earnings.jpg">
<meta name="twitter:title" content="Profil — quiXzoom">
</head>
<body>
<h1 style="position:absolute;left:-9999px;">Zoomer Profile - quiXzoom</h1>
<!-- Nav -->
<div class="nav-bar">
<span class="nav-title">Profil</span>
</div>
<!-- Profile Hero -->
<div class="profile-hero">
<div class="avatar" id="avatar">
🧑
<div class="avatar-badge unverified" id="avatar-badge">⚠️</div>
</div>
<div class="profile-name" id="profile-name">Zoomer</div>
<div class="profile-id" id="profile-id">Laddar...</div>
<div class="rating-row">
<span class="stars">★★★★★</span>
<span class="rating-num" id="rating-num"></span>
<span class="rating-count" id="rating-count">(0 uppdrag)</span>
</div>
</div>
<!-- Stats -->
<div class="stats-grid">
<div class="stat-cell">
<div class="stat-val green" id="stat-completed"></div>
<div class="stat-lbl">Slutförda</div>
</div>
<div class="stat-cell">
<div class="stat-val blue" id="stat-pågående"></div>
<div class="stat-lbl">Pågående</div>
</div>
<div class="stat-cell">
<div class="stat-val yellow" id="stat-earned"></div>
<div class="stat-lbl">Intjänat kr</div>
</div>
</div>
<!-- Onboarding Progress -->
<div class="onboarding-card" id="onboarding-section">
<div class="onboarding-header">
<span class="onboarding-title">🚀 Kom igång</span>
<span class="onboarding-fraction" id="ob-fraction">0 / 3 klara</span>
</div>
<div class="onboarding-track">
<div class="onboarding-fill" id="ob-fill" style="width:0%"></div>
</div>
<div class="onboarding-steps">
<div class="onboarding-step" id="ob-step-1">
<div class="os-icon">🪪</div>
<div class="os-label" id="ob-lbl-1">KYC</div>
</div>
<div class="onboarding-step" id="ob-step-2">
<div class="os-icon">🏦</div>
<div class="os-label" id="ob-lbl-2">Utbetalning</div>
</div>
<div class="onboarding-step" id="ob-step-3">
<div class="os-icon">🎯</div>
<div class="os-label" id="ob-lbl-3">Första uppdrag</div>
</div>
</div>
</div>
<button class="onboarding-cta" id="ob-cta" onclick="goToFirstMission()" disabled>Ta mitt första uppdrag →</button>
<!-- KYC Section -->
<div class="section">
<div class="section-header">Identitetsverifiering</div>
<div class="kyc-card">
<div class="kyc-top">
<div class="kyc-icon unverified" id="kyc-icon">🪪</div>
<div class="kyc-info">
<div class="kyc-title">Identitetsverifiering</div>
<div class="kyc-desc">Verifiera din identitet för att ta emot utbetalningar. Krävs enligt lag (AML).</div>
</div>
</div>
<div class="kyc-status-bar" id="kyc-status-bar">
<span class="status-chip chip-unverified" id="kyc-chip">⚠️ Ej verifierad</span>
<span style="color:var(--label-secondary)">Verifiera för att låsa upp alla uppdrag</span>
</div>
<button class="kyc-btn unverified" id="kyc-btn" onclick="startKYC()">
🪪 Verifiera identitet →
</button>
</div>
</div>
<!-- Earnings Calculator -->
<div class="section">
<div class="section-header">Inkomstpotential</div>
<div class="calc-card">
<div class="calc-header">
<div class="calc-title">💰 Vad kan du tjäna?</div>
<div class="calc-sub">Estimera din månadsinkomst</div>
</div>
<div class="calc-body">
<div class="calc-slider-row">
<span class="calc-label">Tillgänglighet</span>
<span class="calc-value" id="calc-hours-lbl">3 dagar/vecka</span>
</div>
<input type="range" class="calc-slider" id="calc-hours" min="1" max="7" value="3" oninput="updateCalc()">
<div class="calc-slider-row">
<span class="calc-label">Uppdragstyp</span>
<span class="calc-value" id="calc-type-lbl">Fasadscanning (800 kr)</span>
</div>
<select id="calc-type" onchange="updateCalc()" style="width:100%;background:var(--fill-secondary);border:0.5px solid var(--separator);border-radius:10px;padding:10px 14px;font-size:14px;color:var(--label-primary);font-family:var(--font-text);margin-bottom:16px;-webkit-appearance:none">
<option value="800">🏢 Fasadscanning — 800 kr</option>
<option value="1200">🏠 Takscanning — 1 200 kr</option>
<option value="600">🌳 Vegetationsinventering — 600 kr</option>
<option value="1500">🛣️ Väginspektionen — 1 500 kr</option>
<option value="2000">🏗️ Byggnadsdokumentation — 2 000 kr</option>
</select>
<div class="calc-result">
<div class="calc-result-label">Estimerad månadsinkomst</div>
<div class="calc-result-amount" id="calc-amount"></div>
<div class="calc-result-unit">SEK / månad (efter avdrag)</div>
<div class="calc-breakdown">
<div class="calc-breakdown-item">
<div class="calc-breakdown-num" id="calc-missions"></div>
<div class="calc-breakdown-label">Uppdrag/mån</div>
</div>
<div class="calc-breakdown-item">
<div class="calc-breakdown-num" id="calc-gross"></div>
<div class="calc-breakdown-label">Brutto kr</div>
</div>
<div class="calc-breakdown-item">
<div class="calc-breakdown-num">20%</div>
<div class="calc-breakdown-label">quiXzoom-avg</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Referral Program -->
<div class="section">
<div class="section-header">Referral Program</div>
<div class="referral-card">
<div class="referral-header">
<div class="referral-icon">🤝</div>
<div class="referral-info">
<div class="referral-title">Tjäna 200 kr per ny Zoomer</div>
<div class="referral-desc">Dela din kod — du och din vän får 200 kr när de slutför sitt första uppdrag</div>
</div>
</div>
<div class="referral-code-row">
<div class="referral-code" id="referral-code">ZOOM-——</div>
<button class="referral-copy-btn" onclick="copyReferralCode()">📋 Kopiera</button>
</div>
<button class="referral-share-btn" onclick="shareReferral()">📤 Dela via iOS Share Sheet</button>
<div class="referral-stats">
<div class="referral-stat">
<div class="referral-stat-num" id="ref-count">0</div>
<div class="referral-stat-label">Inbjudna</div>
</div>
<div class="referral-stat">
<div class="referral-stat-num" id="ref-converted">0</div>
<div class="referral-stat-label">Aktiverade</div>
</div>
<div class="referral-stat">
<div class="referral-stat-num" id="ref-earned">0 kr</div>
<div class="referral-stat-label">Intjänat</div>
</div>
</div>
</div>
</div>
<!-- Mission breakdown -->
<div class="section">
<div class="section-header">Uppdragstyper</div>
<div class="section-card" id="type-breakdown">
<div style="padding:20px;text-align:center"><div class="spinner"></div></div>
</div>
</div>
<!-- Settings -->
<div class="section">
<div class="section-header">Inställningar</div>
<div class="section-card">
<div class="list-row" onclick="copyId()">
<div class="row-icon-wrap" style="background:rgba(0,122,255,0.15)">🆔</div>
<div class="row-body">
<div class="row-title">Zoomer-ID</div>
<div class="row-sub" id="full-id" style="font-family:var(--font-mono);font-size:11px"></div>
</div>
<span class="row-right">Kopiera <span class="chevron"></span></span>
</div>
<div class="list-row" onclick="openEarnings()">
<div class="row-icon-wrap" style="background:rgba(52,199,89,0.15)">💰</div>
<div class="row-body">
<div class="row-title">Intjäning & utbetalningar</div>
<div class="row-sub">Utbetalningskonto, historik</div>
</div>
<span class="chevron"></span>
</div>
<div class="list-row" onclick="openSupport()">
<div class="row-icon-wrap" style="background:rgba(175,82,222,0.15)">💬</div>
<div class="row-body">
<div class="row-title">Support</div>
<div class="row-sub">support@quixzoom.com</div>
</div>
<span class="chevron"></span>
</div>
<div class="list-row" onclick="openTerms()">
<div class="row-icon-wrap" style="background:rgba(142,142,147,0.15)">📄</div>
<div class="row-body">
<div class="row-title">Användarvillkor & Integritet</div>
<div class="row-sub">Juridisk information</div>
</div>
<span class="chevron"></span>
</div>
</div>
</div>
<!-- App info -->
<div style="text-align:center;padding:8px 16px 8px;color:var(--label-quaternary);font-size:12px">
quiXzoom Zoomer App · v1.0.0 · 2026
</div>
<!-- Toast -->
<div class="toast" id="toast"></div>
<!-- Tab Bar -->
<nav class="tab-bar">
<a class="tab-item" href="zoomer-app.html">
<span class="tab-icon">🎯</span>
<span class="tab-label">Uppdrag</span>
</a>
<a class="tab-item" href="zoomer-earnings.html">
<span class="tab-icon">💰</span>
<span class="tab-label">Intjäning</span>
</a>
<a class="tab-item active" href="zoomer-profile.html">
<span class="tab-icon">👤</span>
<span class="tab-label">Profil</span>
</a>
</nav>
<script>
const API = 'https://api.quixzoom.com/api/qz/missions';
const KYC_API = 'https://api.quixzoom.com/api/qz/kyc';
function getZoomerId() {
let id = localStorage.getItem('qz_zoomer_id');
if (!id) { id = 'zoomer-' + Math.random().toString(36).slice(2,10); localStorage.setItem('qz_zoomer_id', id); }
return id;
}
function getKYCStatus() {
return localStorage.getItem('qz_kyc_status') || 'unverified';
}
function setKYCStatus(s) {
localStorage.setItem('qz_kyc_status', s);
}
function toast(msg, dur=3000) {
const el = document.getElementById('toast');
el.textContent = msg;
el.classList.add('show');
setTimeout(() => el.classList.remove('show'), dur);
}
function formatSEK(n) { return new Intl.NumberFormat('sv-SE').format(n); }
function missionTypeLabel(type) {
const m = { facade_scan:'Fasadscanning', roof_scan:'Takscanning', road_inspection:'Väginspekt.', interior_scan:'Interi ör', vegetation_survey:'Vegetation' };
return m[type] || type;
}
function missionTypeEmoji(type) {
const m = { facade_scan:'🏢', roof_scan:'🏠', road_inspection:'🛣️', interior_scan:'🏚️', vegetation_survey:'🌳', inspection:'🔍' };
return m[type] || '📍';
}
async function loadProfile() {
const zoomerId = getZoomerId();
document.getElementById('profile-id').textContent = zoomerId.slice(0,16) + '...';
document.getElementById('full-id').textContent = zoomerId;
document.getElementById('profile-name').textContent = 'Zoomer · ' + zoomerId.slice(-6).toUpperCase();
try {
const r = await fetch(`${API}/missions`);
const data = await r.json();
const all = data.missions || [];
const mine = all.filter(m => m.zoomer_id === zoomerId);
const completed = mine.filter(m => m.status === 'approved');
const ongoing = mine.filter(m => ['assigned','submitted'].includes(m.status));
const totalEarned = completed.reduce((s,m) => s + m.reward_sek, 0);
document.getElementById('stat-completed').textContent = completed.length;
document.getElementById('stat-pågående').textContent = ongoing.length;
document.getElementById('stat-earned').textContent = formatSEK(totalEarned);
// Rating (mock based on completions)
const rating = completed.length === 0 ? null : Math.min(5, 4.0 + completed.length * 0.1).toFixed(1);
document.getElementById('rating-num').textContent = rating || '—';
document.getElementById('rating-count').textContent = `(${completed.length} uppdrag)`;
// Type breakdown
const typeCounts = {};
mine.forEach(m => {
typeCounts[m.mission_type] = (typeCounts[m.mission_type] || 0) + 1;
});
const maxCount = Math.max(...Object.values(typeCounts), 1);
const breakdownEl = document.getElementById('type-breakdown');
if (Object.keys(typeCounts).length === 0) {
breakdownEl.innerHTML = `<div style="padding:24px;text-align:center;color:var(--label-secondary)">Inga uppdrag ännu</div>`;
} else {
breakdownEl.innerHTML = Object.entries(typeCounts)
.sort((a,b) => b[1]-a[1])
.map(([type, count]) => `
<div class="type-row">
<span class="type-icon">${missionTypeEmoji(type)}</span>
<span class="type-label">${missionTypeLabel(type)}</span>
<div class="type-bar-wrap">
<div class="type-bar" style="width:${Math.round(count/maxCount*100)}%"></div>
</div>
<span class="type-count">${count}st</span>
</div>`).join('');
}
} catch(e) {
console.error(e);
}
// KYC status
renderKYCStatus(getKYCStatus());
}
function renderKYCStatus(status) {
const iconEl = document.getElementById('kyc-icon');
const chipEl = document.getElementById('kyc-chip');
const btnEl = document.getElementById('kyc-btn');
const badgeEl = document.getElementById('avatar-badge');
if (status === 'verified') {
iconEl.className = 'kyc-icon verified';
iconEl.textContent = '✅';
chipEl.className = 'status-chip chip-verified';
chipEl.textContent = '✅ Verifierad';
btnEl.className = 'kyc-btn verified';
btnEl.textContent = '✅ Identitet verifierad';
badgeEl.className = 'avatar-badge verified';
badgeEl.textContent = '✅';
document.getElementById('kyc-status-bar').querySelector('span:last-child').textContent = 'Konto verifierat — alla uppdrag tillgängliga';
} else if (status === 'pending') {
iconEl.className = 'kyc-icon pending';
iconEl.textContent = '⏳';
chipEl.className = 'status-chip chip-pending';
chipEl.textContent = '⏳ Under granskning';
btnEl.className = 'kyc-btn pending';
btnEl.textContent = '⏳ Verifiering pågår...';
badgeEl.textContent = '⏳';
} else {
// unverified
iconEl.className = 'kyc-icon unverified';
iconEl.textContent = '🪪';
chipEl.className = 'status-chip chip-unverified';
chipEl.textContent = '⚠️ Ej verifierad';
btnEl.className = 'kyc-btn unverified';
btnEl.textContent = '🪪 Verifiera identitet →';
}
}
async function startKYC() {
const btn = document.getElementById('kyc-btn');
btn.textContent = '⏳ Startar verifiering...';
btn.disabled = true;
try {
// Skapa unik session
const sessionId = 'kyc-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8);
// Öppna KYC-verifiering i ny flik
const kycUrl = 'https://app.quixzoom.com/kyc-verify.html?session=' + sessionId;
setKYCStatus('pending');
renderKYCStatus('pending');
toast('🪪 Öppnar verifiering...');
window.open(kycUrl, '_blank');
// Starta polling för status
pollKYCStatus(sessionId);
} catch(e) {
console.error('KYC error:', e);
toast('❌ Ett fel uppstod: ' + e.message);
btn.textContent = '🪪 Verifiera identitet →';
btn.disabled = false;
}
}
// Polla KYC-status
async function pollKYCStatus(sessionId) {
const check = async () => {
try {
const res = await fetch(KYC_API + '/status/' + sessionId);
const data = await res.json();
if (data.assurance_level === 'photo_low' || data.status === 'approved') {
setKYCStatus('verified');
renderKYCStatus('verified');
toast('✅ Identitet verifierad!');
return;
} else if (data.assurance_level === 'rejected') {
setKYCStatus('unverified');
renderKYCStatus('unverified');
toast('❌ Verifiering nekad: ' + (data.reject_reason || 'Okänt fel'));
return;
}
setTimeout(check, 5000);
} catch(e) {
console.error('Poll error:', e);
}
};
check();
}
function copyId() {
const id = getZoomerId();
navigator.clipboard?.writeText(id).then(() => toast('📋 ID kopierat!')).catch(() => toast('ID: ' + id));
}
function openEarnings() { window.location.href = 'zoomer-earnings.html'; }
function openSupport() { window.open('https://quixzoom.com/support', '_blank'); }
function openTerms() { window.open('https://quixzoom.com/terms', '_blank'); }
loadProfile();
// === Onboarding Progress Bar ===
function updateOnboarding() {
const kycStatus = getKYCStatus();
const hasBank = localStorage.getItem('qz_bank_linked') === 'true';
const hasFirstMission = parseInt(localStorage.getItem('qz_missions_completed') || '0') > 0;
const steps = [
kycStatus === 'verified',
hasBank,
hasFirstMission
];
const done = steps.filter(Boolean).length;
const pct = Math.round(done / 3 * 100);
document.getElementById('ob-fill').style.width = pct + '%';
document.getElementById('ob-fraction').textContent = done + ' / 3 klara';
const labels = ['ob-lbl-1','ob-lbl-2','ob-lbl-3'];
const texts = ['KYC','Utbetalning','Första uppdrag'];
steps.forEach((s,i) => {
const el = document.getElementById(labels[i]);
el.className = 'os-label ' + (s ? 'done' : (i === done ? 'active' : ''));
if (s) el.textContent = '✅ ' + texts[i];
else if (i === done) el.textContent = ' ' + texts[i];
else el.textContent = texts[i];
});
const cta = document.getElementById('ob-cta');
if (done >= 2) {
// KYC + bank done — can take first mission
cta.disabled = false;
cta.textContent = steps[2] ? '✅ Första uppdrag slutfört!' : '🎯 Ta mitt första uppdrag →';
if (steps[2]) cta.disabled = true;
} else {
cta.disabled = true;
cta.textContent = done === 0 ? '🔒 Slutför KYC för att börja' :
done === 1 ? '🔒 Länka bankkonto för att fortsätta' :
'🎯 Ta mitt första uppdrag →';
}
}
updateOnboarding();
function goToFirstMission() {
window.location.href = 'zoomer-app.html';
}
// === Earnings Calculator ===
function updateCalc() {
const days = parseInt(document.getElementById('calc-hours').value);
const reward = parseInt(document.getElementById('calc-type').value);
const typeEl = document.getElementById('calc-type');
const selectedText = typeEl.options[typeEl.selectedIndex].text;
const rewardMatch = selectedText.match(/(\d[\d\s]+)\s*kr/);
const rewardLabel = rewardMatch ? rewardMatch[0] : reward + ' kr';
// Estimate: ~2 missions per working day
const missionsPerMonth = days * 4 * 2;
const gross = missionsPerMonth * reward;
const net = Math.round(gross * 0.80); // 20% platform fee
const dayLabels = ['','1 dag','2 dagar','3 dagar','4 dagar','5 dagar','6 dagar','7 dagar'];
document.getElementById('calc-hours-lbl').textContent = dayLabels[days] + '/vecka';
document.getElementById('calc-type-lbl').textContent = selectedText.replace(/^[^\s]+ /, '');
document.getElementById('calc-amount').textContent = new Intl.NumberFormat('sv-SE').format(net);
document.getElementById('calc-missions').textContent = missionsPerMonth;
document.getElementById('calc-gross').textContent = new Intl.NumberFormat('sv-SE').format(gross);
}
updateCalc();
// === Referral Program ===
function getReferralCode() {
let code = localStorage.getItem('qz_referral_code');
if (!code) {
const id = getZoomerId().slice(-6).toUpperCase();
code = 'ZOOM-' + id;
localStorage.setItem('qz_referral_code', code);
}
return code;
}
function loadReferralStats() {
const code = getReferralCode();
document.getElementById('referral-code').textContent = code;
// Mock stats from localStorage
const invited = parseInt(localStorage.getItem('qz_ref_invited') || '0');
const converted = parseInt(localStorage.getItem('qz_ref_converted') || '0');
document.getElementById('ref-count').textContent = invited;
document.getElementById('ref-converted').textContent = converted;
document.getElementById('ref-earned').textContent = (converted * 200) + ' kr';
}
loadReferralStats();
function copyReferralCode() {
const code = getReferralCode();
const msg = 'Gå med i quiXzoom med min kod ' + code + ' och tjäna 200 kr på ditt första uppdrag! https://quixzoom.com/join?ref=' + code;
navigator.clipboard?.writeText(msg).then(() => toast('📋 Referral-kod kopierad!')).catch(() => toast('Kod: ' + code));
}
function shareReferral() {
const code = getReferralCode();
const shareData = {
title: 'quiXzoom — Ta drönarppdrag',
text: 'Gå med i quiXzoom med min kod ' + code + ' och vi båda tjänar 200 kr!',
url: 'https://quixzoom.com/join?ref=' + code
};
if (navigator.share) {
navigator.share(shareData).catch(() => copyReferralCode());
} else {
copyReferralCode();
}
}
</script>
</body>
</html>