Feature: Referral-System — User wirbt User
- DB: referral_code (8-stellig, eindeutig) + referred_by zu users Bestehende User erhalten automatisch einen Code - GET /api/auth/referral: Code, Link und Anzahl geworbener User - POST /api/auth/register: ref_code Parameter für Zuordnung - Settings: 'App empfehlen'-Karte mit Link, Teilen-Button und Botschafter-Badges (Botschafter ab 1, Super ab 5, Top ab 10 Einladungen) - app.js: ?ref=CODE aus URL in sessionStorage speichern - APP_VER 222, SW by-v244
This commit is contained in:
parent
82d9e26823
commit
6d757b86c2
6 changed files with 121 additions and 7 deletions
|
|
@ -78,8 +78,10 @@ const API = (() => {
|
|||
login(email, password) {
|
||||
return post('/auth/login', { email, password });
|
||||
},
|
||||
register(email, password, name) {
|
||||
return post('/auth/register', { email, password, name });
|
||||
register(email, password, name, ref_code) {
|
||||
const body = { email, password, name };
|
||||
if (ref_code) body.ref_code = ref_code;
|
||||
return post('/auth/register', body);
|
||||
},
|
||||
logout() {
|
||||
localStorage.removeItem('by_token');
|
||||
|
|
@ -88,6 +90,7 @@ const API = (() => {
|
|||
me() {
|
||||
return get('/auth/me');
|
||||
},
|
||||
referral: () => get('/auth/referral'),
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Router, State-Management, Navigation, Initialisierung.
|
||||
============================================================ */
|
||||
|
||||
const APP_VER = '221'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VER = '222'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
|
||||
const App = (() => {
|
||||
|
||||
|
|
@ -687,6 +687,15 @@ const App = (() => {
|
|||
// INITIALISIERUNG
|
||||
// ----------------------------------------------------------
|
||||
async function init() {
|
||||
// Referral-Code aus URL ?ref=CODE speichern
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const refCode = urlParams.get('ref');
|
||||
if (refCode) {
|
||||
sessionStorage.setItem('by_ref_code', refCode.toUpperCase());
|
||||
// URL bereinigen ohne Reload
|
||||
history.replaceState({}, '', window.location.pathname + window.location.hash);
|
||||
}
|
||||
|
||||
_bindNavigation();
|
||||
await _checkAuth();
|
||||
|
||||
|
|
|
|||
|
|
@ -227,6 +227,17 @@ window.Page_settings = (() => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- App empfehlen -->
|
||||
<div class="card" style="margin-bottom:var(--space-5)" id="referral-card">
|
||||
<div style="padding:var(--space-4);border-bottom:1px solid var(--c-border)">
|
||||
<div style="font-weight:600;margin-bottom:2px">${UI.icon('arrow-square-out')} App empfehlen</div>
|
||||
<div style="font-size:var(--text-xs);color:var(--c-text-secondary)">
|
||||
Lade Freunde ein — jede erfolgreiche Einladung wird in deinem Profil angezeigt.
|
||||
</div>
|
||||
</div>
|
||||
<div id="referral-body" style="padding:var(--space-4)">Lade…</div>
|
||||
</div>
|
||||
|
||||
<!-- App installieren -->
|
||||
<div class="card" style="margin-bottom:var(--space-4)">
|
||||
<div style="padding:var(--space-3) var(--space-4);
|
||||
|
|
@ -470,6 +481,44 @@ window.Page_settings = (() => {
|
|||
? 'Pocket-Modus aktiviert — Bildschirm bleibt bei Aufzeichnung an.'
|
||||
: 'Pocket-Modus deaktiviert.');
|
||||
});
|
||||
|
||||
_loadReferral();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// REFERRAL — Einladungslink laden und rendern
|
||||
// ----------------------------------------------------------
|
||||
async function _loadReferral() {
|
||||
const el = document.getElementById('referral-body');
|
||||
if (!el) return;
|
||||
try {
|
||||
const r = await API.auth.referral();
|
||||
el.innerHTML = `
|
||||
<div style="display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-3)">
|
||||
<div style="flex:1;background:var(--c-surface-2);border-radius:var(--radius-md);
|
||||
padding:var(--space-2) var(--space-3);font-family:monospace;font-size:var(--text-sm);
|
||||
overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${r.link}</div>
|
||||
<button class="btn btn-primary btn-sm" id="ref-share-btn">${UI.icon('arrow-square-out')} Teilen</button>
|
||||
</div>
|
||||
<div style="font-size:var(--text-sm);color:var(--c-text-secondary)">
|
||||
${UI.icon('users')} <strong>${r.count}</strong> ${r.count === 1 ? 'Person' : 'Personen'} über deinen Link registriert
|
||||
</div>
|
||||
${r.count > 0 ? `
|
||||
<div style="margin-top:var(--space-2);display:flex;gap:var(--space-2);flex-wrap:wrap">
|
||||
${r.count >= 1 ? `<span class="badge badge-primary">${UI.icon('star')} Botschafter</span>` : ''}
|
||||
${r.count >= 5 ? `<span class="badge badge-primary">${UI.icon('star')} Super-Botschafter</span>` : ''}
|
||||
${r.count >= 10 ? `<span class="badge badge-primary">${UI.icon('star')} Top-Botschafter</span>` : ''}
|
||||
</div>` : ''}
|
||||
`;
|
||||
document.getElementById('ref-share-btn')?.addEventListener('click', async () => {
|
||||
if (navigator.share) {
|
||||
navigator.share({ title: 'Ban Yaro — Die Hunde-App', text: 'Schau dir Ban Yaro an!', url: r.link }).catch(() => {});
|
||||
} else {
|
||||
await navigator.clipboard.writeText(r.link);
|
||||
UI.toast.success('Link kopiert!');
|
||||
}
|
||||
});
|
||||
} catch { el.innerHTML = '<p style="color:var(--c-text-muted)">Nicht verfügbar.</p>'; }
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
|
@ -662,8 +711,10 @@ window.Page_settings = (() => {
|
|||
}
|
||||
|
||||
await UI.asyncButton(btn, async () => {
|
||||
const result = await API.auth.register(fd.email, fd.password, fd.name.trim());
|
||||
const refCode = sessionStorage.getItem('by_ref_code') || '';
|
||||
const result = await API.auth.register(fd.email, fd.password, fd.name.trim(), refCode || undefined);
|
||||
localStorage.setItem('by_token', result.token);
|
||||
if (refCode) sessionStorage.removeItem('by_ref_code');
|
||||
|
||||
_appState.user = await API.auth.me();
|
||||
document.getElementById('sidebar-username').textContent = _appState.user.name;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Offline-Cache + Push Notifications + Tile-Cache
|
||||
============================================================ */
|
||||
|
||||
const CACHE_VERSION = 'by-v242';
|
||||
const CACHE_VERSION = 'by-v244';
|
||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue