GameKeyManager/steam-gift-manager/templates/index.html

169 lines
7.5 KiB
HTML

{% extends "base.html" %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>{{ _('My Games') }}</h1>
<div>
<a href="{{ url_for('export_games') }}" class="btn btn-outline-secondary">⬇️ {{ _('Export CSV') }}</a>
<a href="{{ url_for('export_pdf') }}" class="btn btn-outline-secondary">⬇️ Export PDF (for sharing)</a>
<a href="{{ url_for('import_games') }}" class="btn btn-outline-secondary">⬆️ {{ _('Import CSV') }}</a>
<a href="{{ url_for('add_game') }}" class="btn btn-primary">+ {{ _('Add New Game') }}</a>
</div>
</div>
{% if games %}
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-dark">
<tr>
<th>{{ _('Cover') }}</th>
<th>{{ _('Name') }}</th>
<th>{{ _('Key') }}</th>
<th>{{ _('Status') }}</th>
<th>{{ _('Created') }}</th>
<th>{{ _('Redeem by') }}</th>
<th>{{ _('Shop') }}</th>
<th>{{ _('Price') }}</th>
<th>{{ _('Actions') }}</th>
</tr>
</thead>
<tbody>
{% for game in games %}
<tr>
<td>
<a href="{{ url_for('game_details', game_id=game.id) }}" title="{{ _('Details') }}">
{% if game.steam_appid %}
<img src="https://cdn.cloudflare.steamstatic.com/steam/apps/{{ game.steam_appid }}/header.jpg"
alt="Steam Header"
class="game-cover"
{% if loop.first %}fetchpriority="high"{% endif %}
width="368"
height="172"
loading="lazy">
{% elif game.url and 'gog.com' in game.url %}
<img src="{{ url_for('static', filename='gog_logo.webp') }}"
alt="GOG Logo"
class="game-cover"
width="368"
height="172"
loading="lazy">
{% endif %}
</a>
</td>
<td>{{ game.name }}</td>
<td class="font-monospace">{{ game.steam_key }}</td>
<td>
{% if game.status == 'nicht eingelöst' %}
<span class="badge bg-warning text-dark">{{ _('Not redeemed') }}</span>
{% elif game.status == 'geschenkt' %}
<span class="badge bg-success">{{ _('Gifted') }}</span>
{% elif game.status == 'eingelöst' %}
<span class="badge bg-secondary">{{ _('Redeemed') }}</span>
{% endif %}
</td>
<td>{{ game.created_at|strftime('%d.%m.%Y') }}</td>
<td>
{% if game.redeem_date %}
<span class="badge bg-danger">{{ game.redeem_date|strftime('%d.%m.%Y') }}</span>
{% endif %}
</td>
<td>
{% if game.url %}
<a href="{{ game.url }}" target="_blank" class="btn btn-sm btn-outline-info">🔗 {{ _('Shop') }}</a>
{% endif %}
</td>
<td>
{% if game.current_price is not none %}
<div {% if game.historical_low is not none %}class="mb-2"{% endif %}>
<div class="text-body-secondary" style="font-size: 0.85em; line-height: 1.2;">
{{ _('Current Deal') }}
</div>
<div style="font-size: 1.05em; line-height: 1.2;">
{{ "%.2f"|format(game.current_price) }} €
{% if game.current_price_shop %}
<span class="d-block text-body-secondary" style="font-size: 0.75em; line-height: 1.1;">({{ game.current_price_shop }})</span>
{% endif %}
</div>
</div>
{% endif %}
{# Historical Low #}
{% if game.historical_low is not none %}
<div>
<div class="text-body-secondary" style="font-size: 0.85em; line-height: 1.2;">
{{ _('Hist. Low') }}
</div>
<div style="font-size: 1.05em; line-height: 1.2;">
{{ "%.2f"|format(game.historical_low) }} €
</div>
</div>
{% endif %}
</td>
<td class="text-nowrap">
{% if game.status == 'geschenkt' %}
<button type="button"
class="btn btn-sm btn-success generate-redeem"
data-game-id="{{ game.id }}"
title="{{ _('Generate redeem link') }}">
🔗
</button>
{% endif %}
<a href="{{ url_for('edit_game', game_id=game.id) }}" class="btn btn-sm btn-warning">✏️</a>
<form method="POST" action="{{ url_for('delete_game', game_id=game.id) }}" class="d-inline">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('{{ _('Really delete?') }}')">🗑️</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script>
document.querySelectorAll('.generate-redeem').forEach(btn => {
btn.addEventListener('click', async function() {
const gameId = this.dataset.gameId;
const flashContainer = document.querySelector('.flash-container');
try {
const response = await fetch(`/generate_redeem/${gameId}`, {
method: 'POST',
headers: {
'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').content,
'Accept': 'application/json'
}
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || '{{ _("Unknown error") }}');
}
if (data.url) {
await navigator.clipboard.writeText(data.url);
// Erfolgsmeldung mit übersetztem Text
flashContainer.innerHTML = `
<div class="alert alert-success alert-dismissible fade show" role="alert">
{{ _("Link copied") }}: <a href="${data.url}" target="_blank">${data.url}</a>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
}
} catch (error) {
// Fehlermeldung mit übersetztem Text
flashContainer.innerHTML = `
<div class="alert alert-danger alert-dismissible fade show" role="alert">
{{ _("Error") }}: ${error.message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
}
});
});
</script>
{% else %}
<div class="alert alert-info">{{ _('No games yet') }}</div>
{% endif %}
{% endblock %}