mirror of
https://github.com/ryankazokas/turbovault-app.git
synced 2026-04-16 22:12:53 +00:00
256 lines
12 KiB
Plaintext
256 lines
12 KiB
Plaintext
<% igdb_enabled = game.new_record? && current_user.igdb_sync_enabled? %>
|
|
|
|
<% if igdb_enabled %>
|
|
<div data-controller="igdb-search"
|
|
data-igdb-search-url-value="<%= search_igdb_games_path %>"
|
|
data-action="click@window->igdb-search#clickOutside">
|
|
<% else %>
|
|
<div>
|
|
<% end %>
|
|
|
|
<%= form_with model: game, class: "space-y-6" do |f| %>
|
|
<% if game.errors.any? %>
|
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
<ul>
|
|
<% game.errors.full_messages.each do |message| %>
|
|
<li><%= message %></li>
|
|
<% end %>
|
|
</ul>
|
|
</div>
|
|
<% end %>
|
|
|
|
<% if igdb_enabled %>
|
|
<!-- IGDB Search Section (only for new games) -->
|
|
<div class="bg-indigo-50 border-l-4 border-indigo-500 p-4 mb-6">
|
|
|
|
<h3 class="text-lg font-semibold text-indigo-900 mb-3">🔍 Search IGDB Database</h3>
|
|
<p class="text-sm text-indigo-700 mb-4">
|
|
Start typing to search the IGDB game database. Select a match to auto-fill details, or add a custom game manually.
|
|
</p>
|
|
|
|
<div class="relative">
|
|
<div class="relative">
|
|
<input type="text"
|
|
placeholder="Search for a game (e.g., 'Zelda Ocarina', 'Mario 64')..."
|
|
class="w-full px-4 py-3 pr-10 rounded-lg border-2 border-indigo-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200"
|
|
data-igdb-search-target="query"
|
|
data-action="input->igdb-search#search"
|
|
autocomplete="off">
|
|
|
|
<button type="button"
|
|
class="absolute right-2 top-2 p-2 text-gray-400 hover:text-gray-600"
|
|
data-action="click->igdb-search#clearSearch"
|
|
title="Clear search">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Results dropdown -->
|
|
<div class="hidden absolute z-10 w-full mt-1 bg-white rounded-lg shadow-lg border border-gray-200 max-h-96 overflow-y-auto"
|
|
data-igdb-search-target="results">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hidden field for IGDB ID -->
|
|
<%= f.hidden_field :igdb_id, "data-igdb-search-target": "igdbId" %>
|
|
</div>
|
|
<% end %>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<%= f.label :title, class: "block text-sm font-medium text-gray-700" %>
|
|
<% if game.new_record? && current_user.igdb_sync_enabled? %>
|
|
<%= f.text_field :title,
|
|
class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500",
|
|
"data-igdb-search-target": "title" %>
|
|
<p class="mt-1 text-xs text-gray-500">Auto-filled from IGDB or enter manually</p>
|
|
<% else %>
|
|
<%= f.text_field :title,
|
|
class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" %>
|
|
<% end %>
|
|
</div>
|
|
|
|
<div>
|
|
<%= f.label :platform_id, class: "block text-sm font-medium text-gray-700" %>
|
|
<% if game.new_record? && current_user.igdb_sync_enabled? %>
|
|
<%= f.collection_select :platform_id, @platforms, :id, :name,
|
|
{ prompt: "Select Platform" },
|
|
class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500",
|
|
"data-igdb-search-target": "platformSelect",
|
|
"data-action": "change->igdb-search#search" %>
|
|
<% else %>
|
|
<%= f.collection_select :platform_id, @platforms, :id, :name,
|
|
{ prompt: "Select Platform" },
|
|
class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" %>
|
|
<% end %>
|
|
</div>
|
|
|
|
<div>
|
|
<%= f.label :format, class: "block text-sm font-medium text-gray-700" %>
|
|
<%= f.select :format, [["Physical", "physical"], ["Digital", "digital"]], { prompt: "Select Format", selected: 'physical' }, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" %>
|
|
</div>
|
|
|
|
<div>
|
|
<%= f.label :date_added, class: "block text-sm font-medium text-gray-700" %>
|
|
<%= f.date_field :date_added, value: game.date_added || Date.current, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" %>
|
|
</div>
|
|
|
|
<div>
|
|
<%= f.label :completion_status, class: "block text-sm font-medium text-gray-700" %>
|
|
<%= f.select :completion_status, [["Backlog", "backlog"], ["Currently Playing", "currently_playing"], ["Completed", "completed"], ["On Hold", "on_hold"], ["Not Playing", "not_playing"]], { prompt: "Select Status", selected: "backlog" }, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" %>
|
|
</div>
|
|
|
|
<div>
|
|
<%= f.label :user_rating, "Rating (1-5 stars)", class: "block text-sm font-medium text-gray-700" %>
|
|
<%= f.number_field :user_rating, min: 1, max: 5, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" %>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<%= f.label :genre_ids, "Genres", class: "block text-sm font-medium text-gray-700" %>
|
|
<%= f.collection_check_boxes :genre_ids, @genres, :id, :name do |b| %>
|
|
<div class="inline-block mr-4">
|
|
<%= b.check_box class: "rounded border-gray-300 text-indigo-600 focus:ring-indigo-500" %>
|
|
<%= b.label class: "ml-2 text-sm text-gray-700" %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<div id="physical-fields" style="<%= 'display: none;' if game.digital? %>">
|
|
<h3 class="text-lg font-medium text-gray-900 mb-4">Physical Game Details</h3>
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<div>
|
|
<%= f.label :condition, class: "block text-sm font-medium text-gray-700" %>
|
|
<%= f.select :condition, [["CIB (Complete in Box)", "cib"], ["Loose", "loose"], ["Sealed", "sealed"], ["Good", "good"], ["Fair", "fair"]], { prompt: "Select Condition", selected: "loose" }, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" %>
|
|
</div>
|
|
|
|
<div>
|
|
<%= f.label :price_paid, class: "block text-sm font-medium text-gray-700" %>
|
|
<%= f.number_field :price_paid, step: 0.01, class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" %>
|
|
</div>
|
|
|
|
<div data-controller="location-autocomplete"
|
|
data-location-autocomplete-url-value="<%= search_locations_games_path %>"
|
|
data-action="click@window->location-autocomplete#clickOutside">
|
|
<%= f.label :location, class: "block text-sm font-medium text-gray-700" %>
|
|
<div class="relative">
|
|
<%= f.text_field :location,
|
|
placeholder: "e.g., Bedroom Shelf A",
|
|
class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500",
|
|
autocomplete: "off",
|
|
data: {
|
|
location_autocomplete_target: "input",
|
|
action: "input->location-autocomplete#search"
|
|
} %>
|
|
|
|
<!-- Autocomplete results dropdown -->
|
|
<div class="hidden absolute z-20 w-full mt-1 bg-white rounded-md shadow-lg border border-gray-200 max-h-48 overflow-y-auto"
|
|
data-location-autocomplete-target="results">
|
|
</div>
|
|
</div>
|
|
<p class="mt-1 text-xs text-gray-500">Start typing to see previously used locations</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="digital-fields" style="<%= 'display: none;' if game.physical? %>">
|
|
<h3 class="text-lg font-medium text-gray-900 mb-4">Digital Game Details</h3>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div data-controller="location-autocomplete"
|
|
data-location-autocomplete-url-value="<%= search_stores_games_path %>"
|
|
data-action="click@window->location-autocomplete#clickOutside">
|
|
<%= f.label :digital_store, "Digital Store/Platform", class: "block text-sm font-medium text-gray-700" %>
|
|
<div class="relative">
|
|
<%= f.text_field :digital_store,
|
|
placeholder: "e.g., Steam, PlayStation Store",
|
|
class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500",
|
|
autocomplete: "off",
|
|
data: {
|
|
location_autocomplete_target: "input",
|
|
action: "input->location-autocomplete#search"
|
|
} %>
|
|
|
|
<!-- Autocomplete results dropdown -->
|
|
<div class="hidden absolute z-20 w-full mt-1 bg-white rounded-md shadow-lg border border-gray-200 max-h-48 overflow-y-auto"
|
|
data-location-autocomplete-target="results">
|
|
</div>
|
|
</div>
|
|
<p class="mt-1 text-xs text-gray-500">Start typing to see previously used stores</p>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<%= f.label :collection_ids, "Collections", class: "block text-sm font-medium text-gray-700 mb-2" %>
|
|
<% if defined?(@collections) && @collections.any? %>
|
|
<div class="space-y-2 max-h-48 overflow-y-auto border border-gray-300 rounded-md p-3 bg-gray-50">
|
|
<% @collections.each do |collection| %>
|
|
<div class="flex items-start">
|
|
<%= check_box_tag "game[collection_ids][]", collection.id,
|
|
game.collection_ids.include?(collection.id),
|
|
id: "game_collection_ids_#{collection.id}",
|
|
class: "rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 mt-1" %>
|
|
<%= label_tag "game_collection_ids_#{collection.id}", class: "ml-2 text-sm" do %>
|
|
<span class="font-medium text-gray-900"><%= collection.name %></span>
|
|
<% if collection.subcollection? %>
|
|
<span class="text-gray-500 text-xs">(subcollection of <%= collection.parent_collection.name %>)</span>
|
|
<% end %>
|
|
<% end %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
<p class="mt-1 text-sm text-gray-500">Select one or more collections for this game</p>
|
|
<% else %>
|
|
<p class="text-gray-500 text-sm">
|
|
No collections yet. <%= link_to "Create a collection", new_collection_path, class: "text-indigo-600 hover:text-indigo-800" %> to organize your games.
|
|
</p>
|
|
<% end %>
|
|
</div>
|
|
|
|
<div>
|
|
<%= f.label :notes, class: "block text-sm font-medium text-gray-700" %>
|
|
<% if game.new_record? && current_user.igdb_sync_enabled? %>
|
|
<%= f.text_area :notes,
|
|
rows: 4,
|
|
class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500",
|
|
placeholder: "Optional notes about this game (can be auto-filled from IGDB)",
|
|
"data-igdb-search-target": "summary" %>
|
|
<p class="mt-1 text-xs text-gray-500">Can be auto-filled from IGDB or add your own notes</p>
|
|
<% else %>
|
|
<%= f.text_area :notes,
|
|
rows: 4,
|
|
class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500",
|
|
placeholder: "Optional notes about this game" %>
|
|
<% end %>
|
|
</div>
|
|
|
|
<div class="flex justify-between">
|
|
<%= f.submit class: "px-6 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700" %>
|
|
<%= link_to "Cancel", game.persisted? ? game : games_path, class: "px-6 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300" %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('turbo:load', function() {
|
|
const formatField = document.querySelector('#game_format');
|
|
const physicalFields = document.querySelector('#physical-fields');
|
|
const digitalFields = document.querySelector('#digital-fields');
|
|
|
|
if (formatField) {
|
|
formatField.addEventListener('change', function() {
|
|
if (this.value === 'physical') {
|
|
physicalFields.style.display = 'block';
|
|
digitalFields.style.display = 'none';
|
|
} else if (this.value === 'digital') {
|
|
physicalFields.style.display = 'none';
|
|
digitalFields.style.display = 'block';
|
|
}
|
|
});
|
|
}
|
|
});
|
|
</script>
|