265 lines
11 KiB
Plaintext
265 lines
11 KiB
Plaintext
<div class="space-y-6">
|
|
<!-- Header -->
|
|
<div class="flex justify-between items-center">
|
|
<div>
|
|
<h1 class="text-3xl font-bold text-gray-900">Storage Locations</h1>
|
|
<p class="text-gray-600">Manage your physical storage locations and QR codes</p>
|
|
</div>
|
|
|
|
<div class="flex gap-2">
|
|
<.link
|
|
navigate={~p"/"}
|
|
class="bg-gray-600 text-white px-4 py-2 rounded-lg hover:bg-gray-700 flex items-center gap-2"
|
|
>
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
|
|
</svg>
|
|
Components
|
|
</.link>
|
|
<button
|
|
phx-click="new"
|
|
class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 flex items-center gap-2"
|
|
>
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
|
|
</svg>
|
|
New Location
|
|
</button>
|
|
|
|
<button
|
|
phx-click="open_qr_scanner"
|
|
class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 flex items-center gap-2"
|
|
>
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z"></path>
|
|
</svg>
|
|
Scan QR Code
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form Modal -->
|
|
<div :if={@show_form} class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
|
|
<div class="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white">
|
|
<div class="mt-3">
|
|
<h3 class="text-lg font-bold text-gray-900 mb-4">
|
|
<%= if @edit_location, do: "Edit Storage Location", else: "New Storage Location" %>
|
|
</h3>
|
|
|
|
<.form for={@form} phx-submit="save" phx-change="validate" class="space-y-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Name</label>
|
|
<.input field={@form[:name]} type="text" placeholder="Enter location name" required />
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Description</label>
|
|
<.input field={@form[:description]} type="textarea" placeholder="Optional description" />
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Parent Location</label>
|
|
<.input
|
|
field={@form[:parent_id]}
|
|
type="select"
|
|
options={[{"None (Root Level)", ""} | parent_options(@edit_location)]}
|
|
/>
|
|
</div>
|
|
|
|
<div class="flex justify-end gap-2">
|
|
<button
|
|
type="button"
|
|
phx-click="cancel"
|
|
class="px-4 py-2 text-sm font-medium text-gray-700 bg-gray-200 rounded-md hover:bg-gray-300"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700"
|
|
>
|
|
<%= if @edit_location, do: "Update", else: "Create" %>
|
|
</button>
|
|
</div>
|
|
</.form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- QR Scanner Modal -->
|
|
<div :if={@qr_scanner_open} class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
|
|
<div class="relative top-10 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white">
|
|
<div class="mt-3">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="text-lg font-bold text-gray-900">QR Code Scanner</h3>
|
|
<button
|
|
phx-click="close_qr_scanner"
|
|
class="text-gray-400 hover:text-gray-600"
|
|
>
|
|
<svg class="w-6 h-6" 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"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- QR Scanner Interface -->
|
|
<div class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center">
|
|
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z"></path>
|
|
</svg>
|
|
<p class="mt-2 text-sm text-gray-600">Camera QR scanner would go here</p>
|
|
<p class="text-xs text-gray-500 mt-1">In a real implementation, this would use JavaScript QR scanning</p>
|
|
|
|
<!-- Test buttons for demo -->
|
|
<div class="mt-4 space-y-2">
|
|
<p class="text-sm font-medium text-gray-700">Test with sample codes:</p>
|
|
<button
|
|
phx-click="qr_scanned"
|
|
phx-value-code="SL:0:1MTKDM:ROOT"
|
|
class="block w-full px-3 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded"
|
|
>
|
|
Scan "Shelf A"
|
|
</button>
|
|
<button
|
|
phx-click="qr_scanned"
|
|
phx-value-code="SL:1:VDI701:1MTKDM"
|
|
class="block w-full px-3 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded"
|
|
>
|
|
Scan "Drawer 1"
|
|
</button>
|
|
<button
|
|
phx-click="qr_scanned"
|
|
phx-value-code="SL:2:GPG9S8:VDI701"
|
|
class="block w-full px-3 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded"
|
|
>
|
|
Scan "Box 1"
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Scanned Codes Display -->
|
|
<div :if={length(@scanned_codes) > 0} class="bg-green-50 border border-green-200 rounded-lg p-4">
|
|
<div class="flex justify-between items-center mb-2">
|
|
<h3 class="text-lg font-medium text-green-800">Recently Scanned</h3>
|
|
<button
|
|
phx-click="clear_scanned"
|
|
class="text-sm text-green-600 hover:text-green-800"
|
|
>
|
|
Clear
|
|
</button>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<div :for={scan <- @scanned_codes} class="flex items-center justify-between bg-white p-2 rounded border">
|
|
<div>
|
|
<span class="font-medium text-gray-900"><%= scan.location.path %></span>
|
|
<span class="text-sm text-gray-600 ml-2">(<%= scan.code %>)</span>
|
|
</div>
|
|
<span class="text-xs text-green-600 bg-green-100 px-2 py-1 rounded">
|
|
Level <%= scan.location.level %>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Storage Locations Table -->
|
|
<div class="bg-white shadow rounded-lg">
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<h3 class="text-lg font-medium text-gray-900">Storage Locations</h3>
|
|
</div>
|
|
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Location
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Level
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
QR Code
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Description
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Actions
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-200">
|
|
<tr :for={location <- @storage_locations} class="hover:bg-gray-50">
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<div class="flex items-center">
|
|
<div class="text-sm font-medium text-gray-900">
|
|
<%= location.path %>
|
|
<!-- DEBUG: Show actual database values -->
|
|
<div class="text-xs text-red-600 mt-1">
|
|
DEBUG - ID: <%= location.id %>, Parent: <%= inspect(location.parent_id) %>, Level: <%= location.level %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-blue-100 text-blue-800">
|
|
<%= format_level(location.level) %>
|
|
</span>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<code class="text-sm bg-gray-100 px-2 py-1 rounded">
|
|
<%= location.qr_code %>
|
|
</code>
|
|
</td>
|
|
<td class="px-6 py-4">
|
|
<div class="text-sm text-gray-900 max-w-xs truncate">
|
|
<%= location.description %>
|
|
</div>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
|
|
<div class="flex space-x-2">
|
|
<.link
|
|
patch={~p"/storage_locations/#{location.id}/edit"}
|
|
class="text-indigo-600 hover:text-indigo-900"
|
|
>
|
|
Edit
|
|
</.link>
|
|
<button
|
|
phx-click="delete"
|
|
phx-value-id={location.id}
|
|
data-confirm="Are you sure?"
|
|
class="text-red-600 hover:text-red-900"
|
|
>
|
|
Delete
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<div :if={length(@storage_locations) == 0} class="text-center py-8">
|
|
<p class="text-gray-500">No storage locations yet. Create one to get started!</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- QR Code Examples -->
|
|
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
|
<h3 class="text-lg font-medium text-blue-800 mb-2">QR Code Examples</h3>
|
|
<p class="text-sm text-blue-700 mb-3">
|
|
Here are some sample QR codes generated for your existing storage locations:
|
|
</p>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div :for={location <- Enum.take(@storage_locations, 4)} class="bg-white p-3 rounded border">
|
|
<div class="text-sm font-medium text-gray-900"><%= location.path %></div>
|
|
<code class="text-xs text-gray-600 bg-gray-100 px-2 py-1 rounded mt-1 inline-block">
|
|
<%= ComponentsElixir.QRCode.generate_qr_data(location) %>
|
|
</code>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div> |