Update from Git Manager GUI
This commit is contained in:
@@ -928,12 +928,19 @@ class WBF_Shortcodes {
|
||||
// Aktiven Tab aus URL lesen (tab=1|2|3), Standard: 1 für eigenes, 2 für fremdes
|
||||
// Tab-ID: numerisch (1–4) oder String-Slug (z.B. 'mc' von der Forum-Bridge)
|
||||
$ptab_raw = $_GET['ptab'] ?? ($is_own ? 1 : 2);
|
||||
$shop_active = class_exists('WIS_DB');
|
||||
$shop_tab_id = 'shop';
|
||||
$allowed_tabs = [1,2,3,4];
|
||||
if ($is_own && $shop_active) $allowed_tabs[] = $shop_tab_id;
|
||||
$active_tab = ctype_digit( (string) $ptab_raw ) ? (int) $ptab_raw : sanitize_key( $ptab_raw );
|
||||
if ( is_int($active_tab) && ! in_array($active_tab, [1,2,3,4]) ) {
|
||||
if (is_int($active_tab) && !in_array($active_tab, [1,2,3,4])) {
|
||||
$active_tab = $is_own ? 1 : 2;
|
||||
}
|
||||
// Tab 1, 3, 4 und String-Tabs nur für eigenes Profil (außer Tab 2 = Aktivität)
|
||||
if ( ! $is_own && $active_tab !== 2 ) $active_tab = 2;
|
||||
if (!is_int($active_tab) && $active_tab !== $shop_tab_id && $active_tab !== 'mc') {
|
||||
$active_tab = $is_own ? 1 : 2;
|
||||
}
|
||||
// Tab 1, 3, 4, "shop" und String-Tabs nur für eigenes Profil (außer Tab 2 = Aktivität)
|
||||
if (!$is_own && $active_tab !== 2) $active_tab = 2;
|
||||
|
||||
ob_start(); ?>
|
||||
<div class="wbf-wrap">
|
||||
@@ -948,6 +955,21 @@ class WBF_Shortcodes {
|
||||
|
||||
<!-- ── SIDEBAR ─────────────────────────────────────────── -->
|
||||
<aside class="wbf-profile-sidebar">
|
||||
<!-- Banner -->
|
||||
<div class="wbf-profile-banner" id="wbfProfileBannerWrap">
|
||||
<?php if ( ! empty($profile->banner_url) ) : ?>
|
||||
<img src="<?php echo esc_url($profile->banner_url); ?>"
|
||||
alt="" id="wbfProfileBanner" class="wbf-profile-banner__img">
|
||||
<?php else : ?>
|
||||
<div class="wbf-profile-banner__placeholder"></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($is_own) : ?>
|
||||
<label class="wbf-banner-upload-btn" title="Banner ändern">
|
||||
<i class="fas fa-image"></i>
|
||||
<input type="file" id="wbfBannerFile" accept="image/*" style="display:none">
|
||||
</label>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="wbf-profile-sidebar__avatar-wrap">
|
||||
<img src="<?php echo esc_url($profile->avatar_url); ?>"
|
||||
alt="<?php echo esc_attr($profile->display_name); ?>"
|
||||
@@ -994,13 +1016,13 @@ class WBF_Shortcodes {
|
||||
<?php if (!empty($profile->bio)): ?>
|
||||
<div class="wbf-profile-sidebar__section">
|
||||
<span class="wbf-profile-sidebar__section-label"><i class="fas fa-align-left"></i> Bio</span>
|
||||
<p><?php echo WBF_BBCode::render($profile->bio); ?></p>
|
||||
<div class="wbf-profile-sidebar__bio-text"><?php echo WBF_BBCode::render($profile->bio); ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($profile->signature)): ?>
|
||||
<div class="wbf-profile-sidebar__section">
|
||||
<span class="wbf-profile-sidebar__section-label"><i class="fas fa-pen-nib"></i> Signatur</span>
|
||||
<p class="wbf-profile-sidebar__sig"><?php echo WBF_BBCode::render($profile->signature); ?></p>
|
||||
<div class="wbf-profile-sidebar__sig"><?php echo WBF_BBCode::render($profile->signature); ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<!-- Öffentliche Custom Fields — nach Kategorie gruppiert -->
|
||||
@@ -1113,6 +1135,12 @@ class WBF_Shortcodes {
|
||||
class="wbf-profile-tab<?php echo $active_tab===4?' active':''; ?>">
|
||||
<i class="fas fa-lock"></i> Sicherheit
|
||||
</a>
|
||||
<?php if ($shop_active): ?>
|
||||
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=shop"
|
||||
class="wbf-profile-tab<?php echo $active_tab==='shop'?' active':''; ?>">
|
||||
<i class="fas fa-shopping-cart"></i> Käufe
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
// „Verbindungen" Tab — immer sichtbar (Discord eingebaut, MC optional)
|
||||
$wbf_has_connections = true;
|
||||
@@ -1124,6 +1152,116 @@ class WBF_Shortcodes {
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<!-- ══════════════════════════════════════════════════
|
||||
TAB SHOP — Käufe (Shop-Plugin)
|
||||
══════════════════════════════════════════════════ -->
|
||||
<?php if ($is_own && $active_tab === 'shop' && $shop_active): ?>
|
||||
<div class="wbf-profile-card">
|
||||
<div class="wbf-profile-card__header">
|
||||
<i class="fas fa-shopping-cart"></i> Deine Käufe
|
||||
</div>
|
||||
<div class="wbf-profile-card__body">
|
||||
<?php
|
||||
$orders = [];
|
||||
if (class_exists('WIS_DB')) {
|
||||
global $wpdb;
|
||||
$username = $profile->username;
|
||||
$orders = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->prefix}wis_orders WHERE player_name = %s ORDER BY created_at DESC",
|
||||
$username
|
||||
));
|
||||
}
|
||||
?>
|
||||
<?php if (empty($orders)): ?>
|
||||
<p class="wbf-profile-empty">Du hast noch keine Käufe getätigt.</p>
|
||||
<?php else: ?>
|
||||
<div class="wbf-shop-orders-list">
|
||||
<table class="wbf-shop-orders-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left">Datum</th>
|
||||
<th style="text-align:center">Anzahl</th>
|
||||
<th style="text-align:right">Gesamtpreis</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($orders as $i => $order):
|
||||
$is_cancelled = strtolower($order->status) === 'cancelled' || strtolower($order->status) === 'storniert';
|
||||
$row_class = $is_cancelled ? 'wbf-shop-order-cancelled' : '';
|
||||
?>
|
||||
<tr class="wbf-shop-order-row <?php echo $row_class; ?>" data-idx="<?php echo $i; ?>">
|
||||
<td><?php echo date_i18n('d.m.Y H:i', strtotime($order->created_at)); ?></td>
|
||||
<td style="text-align:center"><?php echo (int)$order->quantity; ?></td>
|
||||
<td style="text-align:right"><?php echo number_format($order->price * $order->quantity); ?> <?php echo esc_html(get_option('wis_currency_name', 'Coins')); ?></td>
|
||||
<td style="text-align:center">
|
||||
<button class="wbf-btn wbf-btn--sm wbf-shop-order-toggle" data-idx="<?php echo $i; ?>"><i class="fas fa-chevron-down"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="wbf-shop-order-details" id="wbf-shop-order-details-<?php echo $i; ?>" style="display:none">
|
||||
<td colspan="4">
|
||||
<div class="wbf-shop-order-details-inner">
|
||||
<?php /* Artikel-Zeile entfernt, da Item-Liste folgt */ ?>
|
||||
<strong>Einzelpreis:</strong> <?php echo number_format($order->price); ?> <?php echo esc_html(get_option('wis_currency_name', 'Coins')); ?><br>
|
||||
<strong>Status:</strong> <?php echo esc_html(ucfirst($order->status)); ?><br>
|
||||
<?php if (!empty($order->server)): ?><strong>Server:</strong> <?php echo esc_html($order->server); ?><br><?php endif; ?>
|
||||
<?php
|
||||
// Antwort als JSON-Items/Coupon anzeigen
|
||||
$response = $order->response;
|
||||
$decoded = null;
|
||||
if (!empty($response)) {
|
||||
$decoded = json_decode($response, true);
|
||||
}
|
||||
if (is_array($decoded) && isset($decoded['items'])) {
|
||||
echo '<strong>Gekaufte Items:</strong><ul style="margin:.3em 0 .7em 1.2em">';
|
||||
foreach ($decoded['items'] as $item) {
|
||||
$item_id = isset($item['id']) ? $item['id'] : '';
|
||||
$item_id = preg_replace('/^minecraft:/', '', $item_id);
|
||||
$amount = isset($item['amount']) ? (int)$item['amount'] : 1;
|
||||
echo '<li><span style="color:var(--c-primary)">' . esc_html($item_id) . '</span> <span style="color:var(--c-muted)">x' . $amount . '</span></li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
if (isset($decoded['coupon']['code'])) {
|
||||
$c = $decoded['coupon'];
|
||||
echo '<div style="margin:.2em 0 .5em 0"><strong>Coupon:</strong> <span style="color:var(--c-success)">' . esc_html($c['code']) . '</span>';
|
||||
if (isset($c['discount'])) echo ' <span style="color:var(--c-muted)">(' . intval($c['discount']) . '% Rabatt)</span>';
|
||||
echo '</div>';
|
||||
}
|
||||
} elseif (!empty($response)) {
|
||||
echo '<strong>Antwort:</strong> ' . esc_html($response) . '<br>';
|
||||
}
|
||||
?>
|
||||
<span style="font-size:.85em;color:var(--c-muted)">Bestell-ID: <?php echo (int)$order->id; ?></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('.wbf-shop-order-toggle').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
var idx = btn.getAttribute('data-idx');
|
||||
var details = document.getElementById('wbf-shop-order-details-' + idx);
|
||||
if (details.style.display === 'none') {
|
||||
details.style.display = '';
|
||||
btn.querySelector('i').classList.remove('fa-chevron-down');
|
||||
btn.querySelector('i').classList.add('fa-chevron-up');
|
||||
} else {
|
||||
details.style.display = 'none';
|
||||
btn.querySelector('i').classList.remove('fa-chevron-up');
|
||||
btn.querySelector('i').classList.add('fa-chevron-down');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════
|
||||
TAB 1 — Profil bearbeiten + Weitere Profilangaben
|
||||
@@ -1537,6 +1675,122 @@ class WBF_Shortcodes {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ══════════════════════════════════════════════════
|
||||
2FA — Zwei-Faktor-Authentifizierung (TOTP)
|
||||
══════════════════════════════════════════════════ -->
|
||||
<?php if ( class_exists('WBF_TOTP') ) :
|
||||
$wbf_2fa_active = WBF_TOTP::is_enabled_for($current->id);
|
||||
?>
|
||||
<div class="wbf-profile-card wbf-2fa-card" id="wbf2faCard">
|
||||
<div class="wbf-profile-card__header" style="background:rgba(234,179,8,.07);border-bottom-color:rgba(234,179,8,.2)">
|
||||
<i class="fas fa-shield-halved" style="color:#eab308"></i>
|
||||
Zwei-Faktor-Authentifizierung (2FA)
|
||||
<?php if ( $wbf_2fa_active ): ?>
|
||||
<span class="wbf-2fa-badge wbf-2fa-badge--on"><i class="fas fa-check-circle"></i> Aktiv</span>
|
||||
<?php else: ?>
|
||||
<span class="wbf-2fa-badge wbf-2fa-badge--off"><i class="fas fa-circle-xmark"></i> Inaktiv</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="wbf-profile-card__body">
|
||||
|
||||
<!-- ── 2FA bereits aktiv: Deaktivierungs-Formular ── -->
|
||||
<?php if ( $wbf_2fa_active ): ?>
|
||||
<div id="wbf2faActive">
|
||||
<p style="color:var(--c-muted);font-size:.85rem;margin-bottom:1rem">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
Dein Account ist mit einem Authenticator gesichert.
|
||||
Zum Deaktivieren Passwort und aktuellen Code eingeben.
|
||||
</p>
|
||||
<div class="wbf-profile-edit-grid">
|
||||
<div class="wbf-form-row">
|
||||
<label>Aktuelles Passwort</label>
|
||||
<input type="password" id="wbf2faDisablePw" placeholder="••••••" autocomplete="current-password">
|
||||
</div>
|
||||
<div class="wbf-form-row">
|
||||
<label>Authenticator-Code</label>
|
||||
<input type="text" id="wbf2faDisableCode" placeholder="123456"
|
||||
maxlength="6" inputmode="numeric" autocomplete="one-time-code"
|
||||
style="letter-spacing:.2em;font-size:1.15rem;font-family:monospace">
|
||||
</div>
|
||||
</div>
|
||||
<div class="wbf-profile-card__footer">
|
||||
<button class="wbf-btn" id="wbf2faDisableBtn"
|
||||
style="background:rgba(220,38,38,.1);color:#dc2626;border-color:rgba(220,38,38,.3)">
|
||||
<i class="fas fa-shield-xmark"></i> 2FA deaktivieren
|
||||
</button>
|
||||
<span class="wbf-msg" id="wbf2faDisableMsg"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<!-- ── 2FA noch nicht aktiv: Setup-Wizard ── -->
|
||||
<div id="wbf2faInactive">
|
||||
<p style="color:var(--c-muted);font-size:.85rem;margin-bottom:1rem">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
Schütze deinen Account zusätzlich mit einer Authenticator-App
|
||||
(Google Authenticator, Aegis, Bitwarden, Authy, 2FAS…).
|
||||
</p>
|
||||
<button class="wbf-btn wbf-btn--primary" id="wbf2faStartBtn">
|
||||
<i class="fas fa-shield-halved"></i> 2FA einrichten
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Schritt 1: QR-Code scannen -->
|
||||
<div id="wbf2faStep1" style="display:none">
|
||||
<p style="font-size:.85rem;color:var(--c-muted);margin-bottom:.75rem">
|
||||
<strong>Schritt 1:</strong> Scanne diesen QR-Code mit deiner Authenticator-App.
|
||||
</p>
|
||||
<div id="wbf2faQr" style="display:inline-block;padding:10px;background:#fff;border-radius:8px;margin-bottom:.75rem"></div>
|
||||
<p style="font-size:.8rem;color:var(--c-muted);margin-bottom:.5rem">
|
||||
Kein QR-Scanner? Gib diesen Code manuell ein:
|
||||
</p>
|
||||
<code id="wbf2faSecret" style="font-size:.9rem;letter-spacing:.1em;background:var(--c-bg-2);padding:4px 10px;border-radius:4px;user-select:all"></code>
|
||||
<div class="wbf-profile-card__footer" style="margin-top:1rem">
|
||||
<button class="wbf-btn wbf-btn--primary" id="wbf2faToStep2">
|
||||
Weiter <i class="fas fa-arrow-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Schritt 2: Code bestätigen -->
|
||||
<div id="wbf2faStep2" style="display:none">
|
||||
<p style="font-size:.85rem;color:var(--c-muted);margin-bottom:.75rem">
|
||||
<strong>Schritt 2:</strong> Gib den 6-stelligen Code aus deiner App ein.
|
||||
</p>
|
||||
<div class="wbf-form-row" style="max-width:220px">
|
||||
<label>Bestätigungs-Code</label>
|
||||
<input type="text" id="wbf2faVerifyCode" placeholder="123456"
|
||||
maxlength="6" inputmode="numeric" autocomplete="one-time-code"
|
||||
style="letter-spacing:.25em;font-size:1.3rem;text-align:center;font-family:monospace">
|
||||
</div>
|
||||
<div class="wbf-profile-card__footer">
|
||||
<button class="wbf-btn" id="wbf2faBackBtn" style="opacity:.7">
|
||||
<i class="fas fa-arrow-left"></i> Zurück
|
||||
</button>
|
||||
<button class="wbf-btn wbf-btn--primary" id="wbf2faVerifyBtn">
|
||||
<i class="fas fa-check"></i> Bestätigen & aktivieren
|
||||
</button>
|
||||
<span class="wbf-msg" id="wbf2faVerifyMsg"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Schritt 3: Erfolg -->
|
||||
<div id="wbf2faStep3" style="display:none;text-align:center;padding:1.5rem 0">
|
||||
<div style="font-size:2.5rem;margin-bottom:.5rem">🔒</div>
|
||||
<strong style="font-size:1rem;color:var(--c-text)">2FA erfolgreich aktiviert!</strong>
|
||||
<p style="font-size:.85rem;color:var(--c-muted);margin:.5rem 0 0">
|
||||
Ab jetzt wird beim Login ein Code aus deiner App abgefragt.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php endif; // 2fa_active ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; // class_exists WBF_TOTP ?>
|
||||
|
||||
<?php endif; /* end Tab 4 */ ?>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════
|
||||
@@ -1551,7 +1805,7 @@ class WBF_Shortcodes {
|
||||
<div class="wbf-profile-card__header">
|
||||
<i class="fas fa-plug"></i> Verbundene Dienste
|
||||
</div>
|
||||
<div class="wbf-profile-card__body" style="padding:0">
|
||||
<div class="wbf-profile-card__body wbf-connections-body">
|
||||
|
||||
<?php if ( class_exists('MC_Gallery_Forum_Bridge') ) :
|
||||
$mc_content = apply_filters('wbf_profile_tab_content', '', 'minecraft', $profile);
|
||||
@@ -1561,7 +1815,7 @@ class WBF_Shortcodes {
|
||||
<i class="fas fa-cubes" style="color:#65a30d"></i>
|
||||
</div>
|
||||
<div class="wbf-connection-card__head">
|
||||
<span class="wbf-connection-card__title">Minecraft</span>
|
||||
<span class="wbf-connection-card__title">Gallerie Verbindung</span>
|
||||
</div>
|
||||
<div class="wbf-connection-card__content">
|
||||
<?php echo $mc_content; ?>
|
||||
@@ -1569,6 +1823,201 @@ class WBF_Shortcodes {
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
// ── StatusAPI Bridge: Account-Verknüpfung & Ingame-Benachrichtigungen ──
|
||||
$mc_enabled = class_exists( 'WBF_MC_Bridge' ) && WBF_MC_Bridge::is_enabled();
|
||||
$mc_uuid = $mc_enabled ? WBF_MC_Bridge::get_mc_uuid( $profile->id ) : '';
|
||||
$mc_name = $mc_enabled ? WBF_MC_Bridge::get_mc_name( $profile->id ) : '';
|
||||
$mc_linked = ! empty( $mc_uuid );
|
||||
?>
|
||||
<div class="wbf-connection-card">
|
||||
<div class="wbf-connection-card__icon" style="background:rgba(101,163,13,.15);border-color:rgba(101,163,13,.3)">
|
||||
<i class="fas fa-cubes" style="color:#65a30d"></i>
|
||||
</div>
|
||||
<div class="wbf-connection-card__head">
|
||||
<span class="wbf-connection-card__title">Minecraft InGame Verbindung</span>
|
||||
<?php if ( ! $mc_enabled ) : ?>
|
||||
<span class="wbf-connection-badge" style="color:#9ca3af;background:rgba(156,163,175,.1);border-color:rgba(156,163,175,.3)">
|
||||
<i class="fas fa-circle-xmark"></i> Nicht konfiguriert
|
||||
</span>
|
||||
<?php elseif ( $mc_linked ) : ?>
|
||||
<span class="wbf-connection-badge wbf-connection-badge--connected">
|
||||
<i class="fas fa-check-circle"></i> Verbunden
|
||||
</span>
|
||||
<?php else : ?>
|
||||
<span class="wbf-connection-badge wbf-connection-badge--disconnected">
|
||||
<i class="fas fa-circle-xmark"></i> Nicht verbunden
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="wbf-connection-card__content">
|
||||
<?php if ( ! $mc_enabled ) : ?>
|
||||
<p class="wbf-connection-card__desc" style="color:var(--c-muted)">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
Die Minecraft Bridge ist noch nicht eingerichtet.
|
||||
Ein Admin muss sie zuerst in den Forum-Einstellungen aktivieren.
|
||||
</p>
|
||||
<?php elseif ( $mc_linked ) : ?>
|
||||
<div class="wbf-mc-linked-info" style="display:flex;align-items:center;gap:.75rem;margin-bottom:.75rem">
|
||||
<img src="https://mc-heads.net/avatar/<?php echo urlencode( $mc_name ?: $mc_uuid ); ?>/40"
|
||||
alt="" width="40" height="40"
|
||||
style="border-radius:4px;image-rendering:pixelated">
|
||||
<div>
|
||||
<strong style="color:var(--c-text)"><?php echo esc_html( $mc_name ?: $mc_uuid ); ?></strong><br>
|
||||
<small style="color:var(--c-muted);font-size:.75rem"><?php echo esc_html( $mc_uuid ); ?></small>
|
||||
</div>
|
||||
</div>
|
||||
<p style="font-size:.82rem;color:var(--c-muted);margin:.25rem 0 .75rem">
|
||||
<i class="fas fa-bell" style="color:#65a30d"></i>
|
||||
Du erhältst Ingame-Benachrichtigungen bei Antworten, Erwähnungen und PNs.
|
||||
</p>
|
||||
<div id="wbf-mc-msg" style="font-size:.82rem;margin-bottom:.5rem"></div>
|
||||
<button type="button" class="wbf-btn wbf-btn--ghost" id="wbf-mc-unlink-btn"
|
||||
onclick="wbfMcUnlink()">
|
||||
<i class="fas fa-unlink"></i> Verknüpfung aufheben
|
||||
</button>
|
||||
<?php else : ?>
|
||||
<p class="wbf-connection-card__desc">
|
||||
Verknüpfe deinen Minecraft-Account für Ingame-Benachrichtigungen
|
||||
bei neuen Antworten, Erwähnungen und Privatnachrichten.
|
||||
</p>
|
||||
<p style="font-size:.82rem;color:var(--c-muted);margin-bottom:.75rem">
|
||||
<i class="fas fa-terminal"></i>
|
||||
Schritt 1: Token generieren →
|
||||
Schritt 2: <code>/forumlink <token></code> ingame eingeben
|
||||
</p>
|
||||
<div id="wbf-mc-token-box" style="display:none;background:var(--c-surface);border:1px solid var(--c-border);border-radius:8px;padding:.85rem 1rem;margin-bottom:.75rem">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;gap:.5rem;margin-bottom:.4rem">
|
||||
<span style="font-size:.75rem;color:var(--c-muted);text-transform:uppercase;letter-spacing:.05em">Dein Token</span>
|
||||
<span id="wbf-mc-token-timer" style="font-size:.75rem;color:#f97316;font-weight:600"></span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:.5rem">
|
||||
<code id="wbf-mc-token-value"
|
||||
style="font-size:1.4rem;letter-spacing:.25em;font-weight:700;color:var(--c-accent);flex:1"></code>
|
||||
<button type="button" class="wbf-btn wbf-btn--sm" id="wbf-mc-copy-btn"
|
||||
onclick="wbfMcCopyToken()" title="Befehl kopieren">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div style="margin-top:.5rem;font-size:.8rem;color:var(--c-muted)">
|
||||
Ingame eingeben: <code id="wbf-mc-cmd-value">/forumlink </code>
|
||||
</div>
|
||||
<div style="margin-top:.5rem">
|
||||
<div style="height:4px;border-radius:2px;background:var(--c-border);overflow:hidden">
|
||||
<div id="wbf-mc-token-progress"
|
||||
style="height:100%;background:#65a30d;transition:width 1s linear;width:100%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="wbf-mc-msg" style="font-size:.82rem;margin-bottom:.5rem"></div>
|
||||
<button type="button" class="wbf-btn wbf-btn--primary" id="wbf-mc-gen-btn"
|
||||
onclick="wbfMcGenerateToken()">
|
||||
<i class="fas fa-key"></i> Token generieren
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(function(){
|
||||
var _pollInterval = null;
|
||||
var _timerInterval = null;
|
||||
var _expiry = 0;
|
||||
|
||||
window.wbfMcGenerateToken = function() {
|
||||
var btn = document.getElementById('wbf-mc-gen-btn');
|
||||
var msg = document.getElementById('wbf-mc-msg');
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Generiere...';
|
||||
msg.textContent = '';
|
||||
jQuery.post(WBF.ajax_url, { action: 'wbf_mc_generate_token', nonce: WBF.nonce }, function(r) {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '<i class="fas fa-rotate"></i> Neuen Token generieren';
|
||||
if (r.success) {
|
||||
var token = r.data.token;
|
||||
_expiry = Math.floor(Date.now() / 1000) + ((r.data.expires_in || 15) * 60);
|
||||
document.getElementById('wbf-mc-token-value').textContent = token;
|
||||
document.getElementById('wbf-mc-cmd-value').textContent = '/forumlink ' + token;
|
||||
document.getElementById('wbf-mc-token-box').style.display = 'block';
|
||||
wbfMcStartTimer((r.data.expires_in || 15) * 60);
|
||||
wbfMcStartPolling();
|
||||
} else {
|
||||
if (r.data && r.data.linked) {
|
||||
msg.innerHTML = '<span style="color:#16a34a"><i class="fas fa-check-circle"></i> ' + (r.data.message || 'Bereits verknüpft.') + '</span>';
|
||||
setTimeout(function(){ location.reload(); }, 1500);
|
||||
} else {
|
||||
msg.innerHTML = '<span style="color:#dc2626"><i class="fas fa-circle-xmark"></i> ' + (r.data && r.data.message ? r.data.message : 'Fehler') + '</span>';
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function wbfMcStartTimer(seconds) {
|
||||
clearInterval(_timerInterval);
|
||||
var timerEl = document.getElementById('wbf-mc-token-timer');
|
||||
var progressEl = document.getElementById('wbf-mc-token-progress');
|
||||
var total = seconds;
|
||||
_timerInterval = setInterval(function() {
|
||||
var remaining = _expiry - Math.floor(Date.now() / 1000);
|
||||
if (remaining <= 0) {
|
||||
clearInterval(_timerInterval); clearInterval(_pollInterval);
|
||||
if (timerEl) timerEl.textContent = 'Abgelaufen';
|
||||
if (progressEl) progressEl.style.width = '0%';
|
||||
var msg = document.getElementById('wbf-mc-msg');
|
||||
if (msg) msg.innerHTML = '<span style="color:#f97316"><i class="fas fa-clock"></i> Token abgelaufen — bitte neuen generieren.</span>';
|
||||
return;
|
||||
}
|
||||
var m = Math.floor(remaining / 60), s = remaining % 60;
|
||||
if (timerEl) timerEl.textContent = m + ':' + (s < 10 ? '0' : '') + s;
|
||||
if (progressEl) {
|
||||
progressEl.style.width = Math.max(0, (remaining / total) * 100) + '%';
|
||||
progressEl.style.background = remaining < 60 ? '#dc2626' : remaining < 180 ? '#f97316' : '#65a30d';
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function wbfMcStartPolling() {
|
||||
clearInterval(_pollInterval);
|
||||
_pollInterval = setInterval(function() {
|
||||
jQuery.post(WBF.ajax_url, { action: 'wbf_mc_link_status', nonce: WBF.nonce }, function(r) {
|
||||
if (r.success && r.data && r.data.linked) {
|
||||
clearInterval(_pollInterval); clearInterval(_timerInterval);
|
||||
var msg = document.getElementById('wbf-mc-msg');
|
||||
if (msg) msg.innerHTML = '<span style="color:#16a34a"><i class="fas fa-check-circle"></i> ✓ Verknüpft mit <strong>' + (r.data.mc_name || r.data.mc_uuid) + '</strong>! Seite lädt neu...</span>';
|
||||
setTimeout(function(){ location.reload(); }, 1800);
|
||||
}
|
||||
});
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
window.wbfMcCopyToken = function() {
|
||||
var cmd = document.getElementById('wbf-mc-cmd-value').textContent;
|
||||
var btn = document.getElementById('wbf-mc-copy-btn');
|
||||
var done = function() { btn.innerHTML = '<i class="fas fa-check"></i>'; btn.style.color = '#16a34a'; setTimeout(function(){ btn.innerHTML = '<i class="fas fa-copy"></i>'; btn.style.color = ''; }, 2000); };
|
||||
if (navigator.clipboard) { navigator.clipboard.writeText(cmd).then(done); }
|
||||
else { var ta = document.createElement('textarea'); ta.value = cmd; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); done(); }
|
||||
};
|
||||
|
||||
window.wbfMcUnlink = function() {
|
||||
if (!confirm('Minecraft-Verknüpfung wirklich aufheben?')) return;
|
||||
var btn = document.getElementById('wbf-mc-unlink-btn');
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Trenne...';
|
||||
jQuery.post(WBF.ajax_url, { action: 'wbf_mc_unlink', nonce: WBF.nonce }, function(r) {
|
||||
if (r.success) {
|
||||
var msg = document.getElementById('wbf-mc-msg');
|
||||
if (msg) msg.innerHTML = '<span style="color:#16a34a"><i class="fas fa-check"></i> ' + (r.data.message || 'Verknüpfung aufgehoben.') + '</span>';
|
||||
setTimeout(function(){ location.reload(); }, 1200);
|
||||
} else {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '<i class="fas fa-unlink"></i> Verknüpfung aufheben';
|
||||
var msg = document.getElementById('wbf-mc-msg');
|
||||
if (msg) msg.innerHTML = '<span style="color:#dc2626">Fehler: ' + (r.data && r.data.message ? r.data.message : 'Unbekannt') + '</span>';
|
||||
}
|
||||
});
|
||||
};
|
||||
})();
|
||||
</script>
|
||||
|
||||
<?php
|
||||
// ── Discord-Card (eingebaut, kein extra Plugin nötig) ──────────────
|
||||
$discord_meta = WBF_DB::get_user_meta( $profile->id );
|
||||
@@ -1657,6 +2106,7 @@ class WBF_Shortcodes {
|
||||
</div><!-- /.wbf-profile-layout -->
|
||||
</div>
|
||||
</div>
|
||||
<?php self::render_auth_modal(); ?>
|
||||
<?php return ob_get_clean();
|
||||
}
|
||||
|
||||
@@ -2579,16 +3029,7 @@ class WBF_Shortcodes {
|
||||
</div>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?php if (WBF_Roles::level($current->role) >= 80): // Nur Admins/Mods ?>
|
||||
<div style="margin-top:2.5rem;text-align:center">
|
||||
<button class="wbf-btn wbf-btn--primary" id="wbf-discord-sync-btn" type="button">
|
||||
<i class="fab fa-discord"></i> Discord-Rollen-Sync manuell anstoßen
|
||||
</button>
|
||||
<span id="wbf-discord-sync-msg" style="margin-left:1rem;font-size:.95em;display:none"></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (empty($members)): ?>
|
||||
<div class="wbf-empty" style="grid-column:1/-1">
|
||||
<i class="fas fa-users-slash"></i>
|
||||
|
||||
Reference in New Issue
Block a user