Files
turbovault-app/app/views/igdb_matches/index.html.erb
2026-03-28 19:24:29 -04:00

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>