168 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			168 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 %}
 |