Div Erweiterungen
This commit is contained in:
@@ -317,7 +317,7 @@ function displayRunsTable(runs) {
|
||||
|
||||
function displayLocationsTable(locations) {
|
||||
let html = '<div class="table-container"><table class="data-table">';
|
||||
html += '<thead><tr><th>ID</th><th>Name</th><th>Latitude</th><th>Longitude</th><th>Erstellt</th><th>Aktionen</th></tr></thead><tbody>';
|
||||
html += '<thead><tr><th>ID</th><th>Name</th><th>Latitude</th><th>Longitude</th><th>Mindestzeit (s)</th><th>Erstellt</th><th>Aktionen</th></tr></thead><tbody>';
|
||||
|
||||
locations.forEach(location => {
|
||||
html += `<tr>
|
||||
@@ -325,6 +325,7 @@ function displayLocationsTable(locations) {
|
||||
<td>${location.name}</td>
|
||||
<td>${location.latitude}</td>
|
||||
<td>${location.longitude}</td>
|
||||
<td>${location.time_threshold ? (typeof location.time_threshold === 'object' ? location.time_threshold.seconds : location.time_threshold).toFixed(3) : '-'}</td>
|
||||
<td>${new Date(location.created_at).toLocaleDateString('de-DE')}</td>
|
||||
<td class="action-buttons">
|
||||
<button class="btn btn-small btn-warning" onclick="editLocation('${location.id}')">Bearbeiten</button>
|
||||
@@ -393,6 +394,15 @@ function filterData() {
|
||||
case 'adminusers':
|
||||
displayAdminUsersTable(filteredData);
|
||||
break;
|
||||
case 'achievements':
|
||||
if (currentAchievementMode === 'achievements') {
|
||||
currentAchievements = filteredData;
|
||||
displayAchievements();
|
||||
} else {
|
||||
currentPlayers = filteredData;
|
||||
displayPlayers();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,6 +423,13 @@ function refreshData() {
|
||||
case 'system':
|
||||
loadSystemInfo();
|
||||
break;
|
||||
case 'achievements':
|
||||
if (currentAchievementMode === 'achievements') {
|
||||
loadAchievements();
|
||||
} else {
|
||||
loadPlayers();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,6 +573,10 @@ async function handleAddSubmit(e) {
|
||||
successMessage = isEdit ? 'Lauf erfolgreich aktualisiert' : 'Lauf erfolgreich hinzugefügt';
|
||||
method = isEdit ? 'PUT' : 'POST';
|
||||
break;
|
||||
case 'achievements':
|
||||
// Handle achievement form submission
|
||||
await handleAchievementSubmit(formData);
|
||||
return;
|
||||
default:
|
||||
showError('Unbekannter Datentyp');
|
||||
return;
|
||||
@@ -1196,7 +1217,552 @@ function displayBlacklistStats(stats) {
|
||||
statsDiv.innerHTML = html;
|
||||
}
|
||||
|
||||
// ==================== ACHIEVEMENT MANAGEMENT ====================
|
||||
|
||||
let currentAchievementMode = 'achievements'; // 'achievements' or 'players'
|
||||
let currentAchievements = [];
|
||||
let currentPlayers = [];
|
||||
|
||||
// Show achievement management
|
||||
async function showAchievementManagement() {
|
||||
currentDataType = 'achievements';
|
||||
currentAchievementMode = 'achievements';
|
||||
|
||||
document.getElementById('dataTitle').textContent = '🏆 Achievement-Verwaltung';
|
||||
document.getElementById('dataSection').style.display = 'block';
|
||||
|
||||
// Update search placeholder
|
||||
document.getElementById('searchInput').placeholder = 'Achievements durchsuchen...';
|
||||
|
||||
await loadAchievements();
|
||||
}
|
||||
|
||||
// Load all achievements
|
||||
async function loadAchievements() {
|
||||
try {
|
||||
const response = await fetch('/api/v1/admin/achievements');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
currentAchievements = result.data;
|
||||
currentData = result.data; // Set for filtering
|
||||
displayAchievements();
|
||||
} else {
|
||||
showError('Fehler beim Laden der Achievements: ' + result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading achievements:', error);
|
||||
showError('Fehler beim Laden der Achievements');
|
||||
}
|
||||
}
|
||||
|
||||
// Display achievements in table
|
||||
function displayAchievements() {
|
||||
const content = document.getElementById('dataContent');
|
||||
|
||||
if (currentAchievements.length === 0) {
|
||||
content.innerHTML = '<div class="no-data">Keine Achievements gefunden</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `
|
||||
<div class="achievement-controls">
|
||||
<button class="btn btn-success" onclick="showAddAchievementModal()">➕ Neues Achievement</button>
|
||||
<button class="btn" onclick="toggleAchievementMode()">👥 Spieler-Ansicht</button>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Status</th>
|
||||
<th>Icon</th>
|
||||
<th>Name</th>
|
||||
<th>Kategorie</th>
|
||||
<th>Bedingung</th>
|
||||
<th>Punkte</th>
|
||||
<th>Mehrmals</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
currentAchievements.forEach(achievement => {
|
||||
const statusClass = achievement.is_active ? 'active' : 'inactive';
|
||||
const statusText = achievement.is_active ? 'Aktiv' : 'Inaktiv';
|
||||
const multipleText = achievement.can_be_earned_multiple_times ? 'Ja' : 'Nein';
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td><span class="status-badge ${statusClass}">${statusText}</span></td>
|
||||
<td>${achievement.icon || '🏆'}</td>
|
||||
<td>
|
||||
<strong>${achievement.name}</strong>
|
||||
${achievement.name_en ? `<br><small>${achievement.name_en}</small>` : ''}
|
||||
</td>
|
||||
<td>${achievement.category}</td>
|
||||
<td>${achievement.condition_type}: ${achievement.condition_value}</td>
|
||||
<td>${achievement.points}</td>
|
||||
<td>${multipleText}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm" onclick="editAchievement('${achievement.id}')">✏️</button>
|
||||
<button class="btn btn-sm btn-danger" onclick="deleteAchievement('${achievement.id}', '${achievement.name}')">🗑️</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
html += `
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
|
||||
content.innerHTML = html;
|
||||
}
|
||||
|
||||
// Handle achievement form submission
|
||||
async function handleAchievementSubmit(formData) {
|
||||
const isEdit = formData.has('achievement_id');
|
||||
const url = isEdit ?
|
||||
`/api/v1/admin/achievements/${formData.get('achievement_id')}` :
|
||||
'/api/v1/admin/achievements';
|
||||
const method = isEdit ? 'PUT' : 'POST';
|
||||
|
||||
const data = {
|
||||
name: formData.get('name'),
|
||||
name_en: formData.get('name_en') || null,
|
||||
description: formData.get('description'),
|
||||
description_en: formData.get('description_en') || null,
|
||||
category: formData.get('category'),
|
||||
condition_type: formData.get('condition_type'),
|
||||
condition_value: parseInt(formData.get('condition_value')),
|
||||
icon: formData.get('icon') || '🏆',
|
||||
points: parseInt(formData.get('points')) || 10,
|
||||
is_active: formData.has('is_active'),
|
||||
can_be_earned_multiple_times: formData.has('can_be_earned_multiple_times')
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showSuccess(result.message);
|
||||
closeModal();
|
||||
await loadAchievements();
|
||||
} else {
|
||||
showError('Fehler beim Speichern: ' + result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error saving achievement:', error);
|
||||
showError('Fehler beim Speichern des Achievements');
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle between achievements and players view
|
||||
async function toggleAchievementMode() {
|
||||
if (currentAchievementMode === 'achievements') {
|
||||
currentAchievementMode = 'players';
|
||||
document.getElementById('dataTitle').textContent = '👥 Spieler-Achievements';
|
||||
document.getElementById('searchInput').placeholder = 'Spieler durchsuchen...';
|
||||
await loadPlayers();
|
||||
} else {
|
||||
currentAchievementMode = 'achievements';
|
||||
document.getElementById('dataTitle').textContent = '🏆 Achievement-Verwaltung';
|
||||
document.getElementById('searchInput').placeholder = 'Achievements durchsuchen...';
|
||||
await loadAchievements();
|
||||
}
|
||||
}
|
||||
|
||||
// Load all players with achievement statistics
|
||||
async function loadPlayers() {
|
||||
try {
|
||||
const response = await fetch('/api/v1/admin/achievements/players');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
currentPlayers = result.data;
|
||||
currentData = result.data; // Set for filtering
|
||||
displayPlayers();
|
||||
} else {
|
||||
showError('Fehler beim Laden der Spieler: ' + result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading players:', error);
|
||||
showError('Fehler beim Laden der Spieler');
|
||||
}
|
||||
}
|
||||
|
||||
// Display players in table
|
||||
function displayPlayers() {
|
||||
const content = document.getElementById('dataContent');
|
||||
|
||||
if (currentPlayers.length === 0) {
|
||||
content.innerHTML = '<div class="no-data">Keine Spieler gefunden</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `
|
||||
<div class="achievement-controls">
|
||||
<button class="btn" onclick="toggleAchievementMode()">🏆 Achievement-Ansicht</button>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Spieler</th>
|
||||
<th>Abgeschlossen</th>
|
||||
<th>Gesamt</th>
|
||||
<th>Fortschritt</th>
|
||||
<th>Punkte</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
currentPlayers.forEach(player => {
|
||||
const progressPercentage = player.completion_percentage || 0;
|
||||
const progressBar = `
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" style="width: ${progressPercentage}%"></div>
|
||||
<span class="progress-text">${progressPercentage}%</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td><strong>${player.firstname} ${player.lastname}</strong></td>
|
||||
<td>${player.completed_achievements}</td>
|
||||
<td>${player.total_achievements}</td>
|
||||
<td>${progressBar}</td>
|
||||
<td>${player.total_points}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm" onclick="viewPlayerAchievements('${player.id}', '${player.firstname} ${player.lastname}')">👁️</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
html += `
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
|
||||
content.innerHTML = html;
|
||||
}
|
||||
|
||||
// Show add achievement modal
|
||||
function showAddAchievementModal() {
|
||||
const modal = document.getElementById('addModal');
|
||||
const modalTitle = document.getElementById('modalTitle');
|
||||
const formFields = document.getElementById('formFields');
|
||||
|
||||
modalTitle.textContent = 'Neues Achievement erstellen';
|
||||
|
||||
formFields.innerHTML = `
|
||||
<div class="form-group">
|
||||
<label for="achievement_name">Name *</label>
|
||||
<input type="text" id="achievement_name" name="name" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_name_en">Name (Englisch)</label>
|
||||
<input type="text" id="achievement_name_en" name="name_en">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_description">Beschreibung *</label>
|
||||
<textarea id="achievement_description" name="description" required></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_description_en">Beschreibung (Englisch)</label>
|
||||
<textarea id="achievement_description_en" name="description_en"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_category">Kategorie *</label>
|
||||
<select id="achievement_category" name="category" required>
|
||||
<option value="">Kategorie wählen</option>
|
||||
<option value="consistency">Konsistenz</option>
|
||||
<option value="improvement">Verbesserung</option>
|
||||
<option value="seasonal">Saisonal</option>
|
||||
<option value="monthly">Monatlich</option>
|
||||
<option value="best_time">Beste Zeit</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_condition_type">Bedingungstyp *</label>
|
||||
<input type="text" id="achievement_condition_type" name="condition_type" required placeholder="z.B. first_time, attempts_per_day">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_condition_value">Bedingungswert *</label>
|
||||
<input type="number" id="achievement_condition_value" name="condition_value" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_icon">Icon</label>
|
||||
<input type="text" id="achievement_icon" name="icon" value="🏆">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_points">Punkte</label>
|
||||
<input type="number" id="achievement_points" name="points" value="10">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" id="achievement_is_active" name="is_active" checked>
|
||||
Aktiv
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" id="achievement_multiple" name="can_be_earned_multiple_times">
|
||||
Kann mehrmals erreicht werden
|
||||
</label>
|
||||
</div>
|
||||
`;
|
||||
|
||||
modal.style.display = 'block';
|
||||
}
|
||||
|
||||
// Edit achievement
|
||||
async function editAchievement(achievementId) {
|
||||
const achievement = currentAchievements.find(a => a.id === achievementId);
|
||||
if (!achievement) return;
|
||||
|
||||
const modal = document.getElementById('addModal');
|
||||
const modalTitle = document.getElementById('modalTitle');
|
||||
const formFields = document.getElementById('formFields');
|
||||
|
||||
modalTitle.textContent = 'Achievement bearbeiten';
|
||||
|
||||
formFields.innerHTML = `
|
||||
<input type="hidden" id="achievement_id" value="${achievement.id}">
|
||||
<div class="form-group">
|
||||
<label for="achievement_name">Name *</label>
|
||||
<input type="text" id="achievement_name" name="name" value="${achievement.name}" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_name_en">Name (Englisch)</label>
|
||||
<input type="text" id="achievement_name_en" name="name_en" value="${achievement.name_en || ''}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_description">Beschreibung *</label>
|
||||
<textarea id="achievement_description" name="description" required>${achievement.description}</textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_description_en">Beschreibung (Englisch)</label>
|
||||
<textarea id="achievement_description_en" name="description_en">${achievement.description_en || ''}</textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_category">Kategorie *</label>
|
||||
<select id="achievement_category" name="category" required>
|
||||
<option value="consistency" ${achievement.category === 'consistency' ? 'selected' : ''}>Konsistenz</option>
|
||||
<option value="improvement" ${achievement.category === 'improvement' ? 'selected' : ''}>Verbesserung</option>
|
||||
<option value="seasonal" ${achievement.category === 'seasonal' ? 'selected' : ''}>Saisonal</option>
|
||||
<option value="monthly" ${achievement.category === 'monthly' ? 'selected' : ''}>Monatlich</option>
|
||||
<option value="best_time" ${achievement.category === 'best_time' ? 'selected' : ''}>Beste Zeit</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_condition_type">Bedingungstyp *</label>
|
||||
<input type="text" id="achievement_condition_type" name="condition_type" value="${achievement.condition_type}" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_condition_value">Bedingungswert *</label>
|
||||
<input type="number" id="achievement_condition_value" name="condition_value" value="${achievement.condition_value}" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_icon">Icon</label>
|
||||
<input type="text" id="achievement_icon" name="icon" value="${achievement.icon || '🏆'}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="achievement_points">Punkte</label>
|
||||
<input type="number" id="achievement_points" name="points" value="${achievement.points}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" id="achievement_is_active" name="is_active" ${achievement.is_active ? 'checked' : ''}>
|
||||
Aktiv
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" id="achievement_multiple" name="can_be_earned_multiple_times" ${achievement.can_be_earned_multiple_times ? 'checked' : ''}>
|
||||
Kann mehrmals erreicht werden
|
||||
</label>
|
||||
</div>
|
||||
`;
|
||||
|
||||
modal.style.display = 'block';
|
||||
}
|
||||
|
||||
// Delete achievement
|
||||
function deleteAchievement(achievementId, achievementName) {
|
||||
document.getElementById('confirmMessage').textContent = `Möchten Sie das Achievement "${achievementName}" wirklich deaktivieren?`;
|
||||
document.getElementById('confirmYes').onclick = () => confirmDeleteAchievement(achievementId);
|
||||
document.getElementById('confirmModal').style.display = 'block';
|
||||
}
|
||||
|
||||
// Confirm delete achievement
|
||||
async function confirmDeleteAchievement(achievementId) {
|
||||
try {
|
||||
const response = await fetch(`/api/v1/admin/achievements/${achievementId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showSuccess(result.message);
|
||||
closeModal();
|
||||
await loadAchievements();
|
||||
} else {
|
||||
showError('Fehler beim Löschen: ' + result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting achievement:', error);
|
||||
showError('Fehler beim Löschen des Achievements');
|
||||
}
|
||||
}
|
||||
|
||||
// View player achievements
|
||||
async function viewPlayerAchievements(playerId, playerName) {
|
||||
try {
|
||||
const response = await fetch(`/api/v1/admin/achievements/players/${playerId}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showPlayerAchievementsModal(result.player, result.data);
|
||||
} else {
|
||||
showError('Fehler beim Laden der Spieler-Achievements: ' + result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading player achievements:', error);
|
||||
showError('Fehler beim Laden der Spieler-Achievements');
|
||||
}
|
||||
}
|
||||
|
||||
// Show player achievements modal
|
||||
function showPlayerAchievementsModal(player, achievements) {
|
||||
const modal = document.getElementById('addModal');
|
||||
const modalTitle = document.getElementById('modalTitle');
|
||||
const formFields = document.getElementById('formFields');
|
||||
|
||||
modalTitle.textContent = `Achievements von ${player.firstname} ${player.lastname}`;
|
||||
|
||||
let html = `
|
||||
<div class="player-achievements">
|
||||
<div class="achievement-stats">
|
||||
<div class="stat-item">
|
||||
<strong>Abgeschlossen:</strong> ${achievements.filter(a => a.is_completed).length} / ${achievements.length}
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<strong>Gesamtpunkte:</strong> ${achievements.filter(a => a.is_completed).reduce((sum, a) => sum + a.points, 0)}
|
||||
</div>
|
||||
</div>
|
||||
<div class="achievements-list">
|
||||
`;
|
||||
|
||||
achievements.forEach(achievement => {
|
||||
const statusClass = achievement.is_completed ? 'completed' : 'not-completed';
|
||||
const statusIcon = achievement.is_completed ? '✅' : '❌';
|
||||
const completionCount = achievement.completion_count || 0;
|
||||
|
||||
html += `
|
||||
<div class="achievement-item ${statusClass}">
|
||||
<div class="achievement-header">
|
||||
<span class="achievement-icon">${achievement.icon}</span>
|
||||
<span class="achievement-name">${achievement.name}</span>
|
||||
<span class="achievement-status">${statusIcon}</span>
|
||||
</div>
|
||||
<div class="achievement-details">
|
||||
<p>${achievement.description}</p>
|
||||
<div class="achievement-meta">
|
||||
<span>Kategorie: ${achievement.category}</span>
|
||||
<span>Punkte: ${achievement.points}</span>
|
||||
${achievement.is_completed ? `<span>Erreicht: ${new Date(achievement.earned_at).toLocaleDateString('de-DE')}</span>` : ''}
|
||||
${completionCount > 1 ? `<span>Anzahl: ${completionCount}</span>` : ''}
|
||||
</div>
|
||||
<div class="achievement-actions">
|
||||
${!achievement.is_completed ?
|
||||
`<button class="btn btn-sm btn-success" onclick="awardAchievement('${player.id}', '${achievement.id}', '${achievement.name}')">Vergeben</button>` :
|
||||
`<button class="btn btn-sm btn-danger" onclick="revokeAchievement('${player.id}', '${achievement.id}', '${achievement.name}')">Entfernen</button>`
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
html += `
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
formFields.innerHTML = html;
|
||||
modal.style.display = 'block';
|
||||
}
|
||||
|
||||
// Award achievement to player
|
||||
async function awardAchievement(playerId, achievementId, achievementName) {
|
||||
try {
|
||||
const response = await fetch(`/api/v1/admin/achievements/players/${playerId}/award`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
achievement_id: achievementId,
|
||||
progress: 1
|
||||
})
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showSuccess(result.message);
|
||||
// Refresh player achievements
|
||||
await viewPlayerAchievements(playerId, '');
|
||||
} else {
|
||||
showError('Fehler beim Vergeben: ' + result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error awarding achievement:', error);
|
||||
showError('Fehler beim Vergeben des Achievements');
|
||||
}
|
||||
}
|
||||
|
||||
// Revoke achievement from player
|
||||
async function revokeAchievement(playerId, achievementId, achievementName) {
|
||||
if (!confirm(`Möchten Sie das Achievement "${achievementName}" wirklich entfernen?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/v1/admin/achievements/players/${playerId}/revoke`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
achievement_id: achievementId
|
||||
})
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showSuccess(result.message);
|
||||
// Refresh player achievements
|
||||
await viewPlayerAchievements(playerId, '');
|
||||
} else {
|
||||
showError('Fehler beim Entfernen: ' + result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error revoking achievement:', error);
|
||||
showError('Fehler beim Entfernen des Achievements');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user