mirror of
https://github.com/ryankazokas/turbovault-app.git
synced 2026-04-17 05:12:51 +00:00
194 lines
9.3 KiB
Plaintext
194 lines
9.3 KiB
Plaintext
<%
|
|
# Auto-refresh if user just started a sync or has games being processed
|
|
has_unmatched = @unmatched_games > 0 && @pending_review_count == 0
|
|
just_synced = current_user.igdb_last_synced_at && current_user.igdb_last_synced_at > 5.minutes.ago
|
|
should_auto_refresh = has_unmatched && just_synced
|
|
%>
|
|
|
|
<% if should_auto_refresh %>
|
|
<meta http-equiv="refresh" content="30">
|
|
<div class="bg-blue-100 border-l-4 border-blue-500 p-4 mb-4">
|
|
<div class="flex items-center">
|
|
<svg class="animate-spin h-5 w-5 text-blue-500 mr-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
<span class="text-blue-700">Processing games... Page will auto-refresh every 30 seconds.</span>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
|
|
<div class="max-w-6xl mx-auto">
|
|
<div class="flex justify-between items-center mb-6">
|
|
<h1 class="text-3xl font-bold">IGDB Game Matching</h1>
|
|
<%= button_to "Sync Now", sync_now_igdb_matches_path, method: :post, class: "px-4 py-2 bg-indigo-600 text-white rounded hover:bg-indigo-700" %>
|
|
</div>
|
|
|
|
<!-- Stats -->
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
|
|
<div class="bg-white p-6 rounded-lg shadow">
|
|
<div class="text-gray-500 text-sm">Matched Games</div>
|
|
<div class="text-3xl font-bold text-green-600"><%= @matched_games %></div>
|
|
</div>
|
|
|
|
<div class="bg-white p-6 rounded-lg shadow">
|
|
<div class="text-gray-500 text-sm">Unmatched Games</div>
|
|
<div class="text-3xl font-bold text-gray-600"><%= @unmatched_games %></div>
|
|
</div>
|
|
|
|
<div class="bg-white p-6 rounded-lg shadow">
|
|
<div class="text-gray-500 text-sm">Pending Review</div>
|
|
<div class="text-3xl font-bold text-yellow-600"><%= @pending_review_count %></div>
|
|
</div>
|
|
</div>
|
|
|
|
<% if current_user.igdb_last_synced_at %>
|
|
<div class="bg-blue-50 border-l-4 border-blue-400 p-4 mb-6">
|
|
<p class="text-sm text-blue-700">
|
|
<strong>Last synced:</strong> <%= time_ago_in_words(current_user.igdb_last_synced_at) %> ago
|
|
</p>
|
|
</div>
|
|
<% end %>
|
|
|
|
<% if @pending_suggestions.empty? %>
|
|
<div class="bg-white p-8 rounded-lg shadow text-center">
|
|
<% if @unmatched_games > 0 %>
|
|
<p class="text-gray-600 mb-4">No pending matches to review. Click "Sync Now" to search IGDB for your games!</p>
|
|
<%= button_to "Sync Now", sync_now_igdb_matches_path, method: :post, class: "px-6 py-3 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700" %>
|
|
<% else %>
|
|
<p class="text-gray-600">All your games are matched with IGDB! 🎉</p>
|
|
<% end %>
|
|
</div>
|
|
<% else %>
|
|
<div class="space-y-8">
|
|
<% @pending_suggestions.each do |game, suggestions| %>
|
|
<div class="bg-white rounded-lg shadow overflow-hidden">
|
|
<!-- Game Header -->
|
|
<div class="bg-gray-50 px-6 py-4 border-b">
|
|
<div class="flex justify-between items-start">
|
|
<div>
|
|
<h2 class="text-xl font-bold text-gray-900"><%= game.title %></h2>
|
|
<p class="text-sm text-gray-600">
|
|
<%= game.platform.name %> · <%= game.format.titleize %>
|
|
<% if game.date_added %>
|
|
· Added <%= game.date_added.strftime("%b %Y") %>
|
|
<% end %>
|
|
</p>
|
|
</div>
|
|
<span class="px-3 py-1 text-sm font-semibold rounded-full <%=
|
|
case game.igdb_match_status
|
|
when 'high_confidence' then 'bg-green-100 text-green-800'
|
|
when 'medium_confidence' then 'bg-yellow-100 text-yellow-800'
|
|
else 'bg-gray-100 text-gray-800'
|
|
end
|
|
%>">
|
|
<%= game.igdb_match_status&.titleize || 'Needs Review' %>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Suggestions -->
|
|
<div class="p-6">
|
|
<h3 class="text-lg font-semibold mb-4">
|
|
Suggested Matches from IGDB:
|
|
</h3>
|
|
|
|
<div class="space-y-4">
|
|
<% suggestions.each do |suggestion| %>
|
|
<div class="border rounded-lg p-4 hover:bg-gray-50 transition">
|
|
<div class="flex gap-4">
|
|
<!-- Cover Image -->
|
|
<div class="flex-shrink-0">
|
|
<% if suggestion.igdb_cover_url.present? %>
|
|
<%= image_tag suggestion.cover_image_url("cover_big"),
|
|
alt: suggestion.igdb_name,
|
|
class: "w-24 h-32 object-cover rounded shadow" %>
|
|
<% else %>
|
|
<div class="w-24 h-32 bg-gray-200 rounded flex items-center justify-center">
|
|
<span class="text-gray-400 text-xs">No Cover</span>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<!-- Match Info -->
|
|
<div class="flex-1">
|
|
<div class="flex justify-between items-start mb-2">
|
|
<div class="flex-1">
|
|
<h4 class="text-lg font-semibold text-gray-900"><%= suggestion.igdb_name %></h4>
|
|
<div class="text-sm text-gray-600 space-x-2 mb-2">
|
|
<span><%= suggestion.igdb_platform_name %></span>
|
|
<% if suggestion.igdb_release_date %>
|
|
<span>·</span>
|
|
<span><%= suggestion.igdb_release_date.year %></span>
|
|
<% end %>
|
|
</div>
|
|
|
|
<!-- Summary -->
|
|
<% if suggestion.igdb_summary.present? %>
|
|
<p class="text-sm text-gray-700 leading-relaxed mb-2" style="display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">
|
|
<%= suggestion.igdb_summary %>
|
|
</p>
|
|
<% end %>
|
|
|
|
<!-- Genres -->
|
|
<% if suggestion.igdb_genres.present? && suggestion.igdb_genres.any? %>
|
|
<div class="flex flex-wrap gap-1 mt-2">
|
|
<% suggestion.igdb_genres.first(5).each do |genre| %>
|
|
<span class="px-2 py-0.5 bg-indigo-100 text-indigo-700 rounded text-xs">
|
|
<%= genre %>
|
|
</span>
|
|
<% end %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<!-- Confidence Score -->
|
|
<div class="text-right">
|
|
<div class="text-2xl font-bold <%=
|
|
if suggestion.confidence_score >= 80
|
|
'text-green-600'
|
|
elsif suggestion.confidence_score >= 60
|
|
'text-yellow-600'
|
|
else
|
|
'text-gray-600'
|
|
end
|
|
%>">
|
|
<%= suggestion.confidence_score.to_i %>%
|
|
</div>
|
|
<div class="text-xs text-gray-500">match</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="flex gap-2 mt-4">
|
|
<%= button_to "✓ Approve This Match", approve_igdb_match_path(suggestion),
|
|
method: :post,
|
|
class: "px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700 text-sm font-medium",
|
|
data: { turbo_confirm: "Link '#{suggestion.game.title}' to '#{suggestion.igdb_name}'? This will import cover art, genres, and metadata." } %>
|
|
|
|
<%= button_to "✗ Not This One", reject_igdb_match_path(suggestion),
|
|
method: :post,
|
|
class: "px-4 py-2 bg-gray-200 text-gray-700 rounded hover:bg-gray-300 text-sm font-medium",
|
|
data: { turbo_confirm: "Reject this match for '#{suggestion.game.title}'?" } %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<!-- Reject All Option -->
|
|
<div class="mt-6 pt-6 border-t">
|
|
<p class="text-sm text-gray-600 mb-2">None of these match?</p>
|
|
<%= button_to "Reject All Suggestions", reject_igdb_match_path(suggestions.first),
|
|
method: :post,
|
|
class: "px-4 py-2 bg-red-100 text-red-700 rounded hover:bg-red-200 text-sm font-medium",
|
|
data: { turbo_confirm: "Reject all #{suggestions.count} suggestions for '#{game.title}'? You can manually match it later if needed." } %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|