sackey e3b2b220d2
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run
Enhance UI and functionality across various components
- Increased icon sizes in service items, service orders, users, and technician management for better visibility.
- Added custom loading indicators with appropriate icons in search fields for vehicles, work orders, and technicians.
- Introduced invoice management routes for better organization and access control.
- Created a new test for the estimate PDF functionality to ensure proper rendering and data integrity.
2025-08-16 14:36:58 +00:00

253 lines
14 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div class="space-y-6">
<!-- Enhanced Header -->
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div>
<h1 class="text-3xl font-bold text-zinc-900 dark:text-white dark:text-white">Stock Movements</h1>
<p class="mt-2 text-lg text-zinc-600 dark:text-zinc-400 dark:text-gray-300">
Track {{ number_format($movements->total()) }} inventory transactions and adjustments
</p>
</div>
<div class="flex flex-col sm:flex-row gap-3">
<flux:button wire:navigate href="{{ route('inventory.parts.index') }}" variant="outline" icon="cube" size="sm">
View Parts
</flux:button>
<flux:button wire:navigate href="{{ route('inventory.stock-movements.create') }}" variant="primary" icon="plus" size="sm">
Record Movement
</flux:button>
</div>
</div>
<!-- Enhanced Filters -->
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700 border border-zinc-200 dark:border-zinc-700">
<div class="p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-zinc-900 dark:text-white dark:text-white">Filter Movements</h3>
<flux:button wire:click="clearFilters" variant="outline" size="xs">
Clear All
</flux:button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 gap-4">
<!-- Enhanced Search -->
<div class="lg:col-span-2">
<flux:field>
<flux:label>Search Parts</flux:label>
<flux:input
wire:model.live.debounce.300ms="search"
placeholder="Part name or number..."
icon="magnifying-glass"
/>
</flux:field>
</div>
<!-- Movement Type Filter -->
<div>
<flux:field>
<flux:label>Movement Type</flux:label>
<flux:select wire:model.live="typeFilter">
<option value="">All Types</option>
<option value="in">📈 Stock In</option>
<option value="out">📉 Stock Out</option>
<option value="adjustment">⚖️ Adjustment</option>
<option value="transfer">🔄 Transfer</option>
<option value="return">↩️ Return</option>
</flux:select>
</flux:field>
</div>
<!-- Part Filter -->
<div>
<flux:field>
<flux:label>Specific Part</flux:label>
<flux:select wire:model.live="partFilter">
<option value="">All Parts</option>
@foreach($parts as $part)
<option value="{{ $part->id }}">{{ $part->name }} ({{ $part->part_number }})</option>
@endforeach
</flux:select>
</flux:field>
</div>
<!-- Date From -->
<div>
<flux:field>
<flux:label>From Date</flux:label>
<flux:input wire:model.live="dateFrom" type="date" />
</flux:field>
</div>
<!-- Date To -->
<div>
<flux:field>
<flux:label>To Date</flux:label>
<flux:input wire:model.live="dateTo" type="date" />
</flux:field>
</div>
</div>
<!-- Active Filters Display -->
<div class="mt-4 flex flex-wrap gap-2">
@if($search)
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">
Search: "{{ $search }}"
<button wire:click="$set('search', '')" class="ml-2 text-blue-600 hover:text-blue-800">×</button>
</span>
@endif
@if($typeFilter)
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200">
Type: {{ ucfirst($typeFilter) }}
<button wire:click="$set('typeFilter', '')" class="ml-2 text-green-600 hover:text-green-800">×</button>
</span>
@endif
@if($partFilter)
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200">
Part: {{ $parts->firstWhere('id', $partFilter)?->name ?? 'Unknown' }}
<button wire:click="$set('partFilter', '')" class="ml-2 text-purple-600 hover:text-purple-800">×</button>
</span>
@endif
@if($dateFrom)
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200">
From: {{ $dateFrom }}
<button wire:click="$set('dateFrom', '')" class="ml-2 text-orange-600 hover:text-orange-800">×</button>
</span>
@endif
@if($dateTo)
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200">
To: {{ $dateTo }}
<button wire:click="$set('dateTo', '')" class="ml-2 text-orange-600 hover:text-orange-800">×</button>
</span>
@endif
</div>
</div>
</div>
<!-- Results Summary -->
<div class="flex items-center justify-between text-sm text-zinc-600 dark:text-zinc-400 dark:text-gray-400">
<div>
Showing {{ $movements->firstItem() ?? 0 }} to {{ $movements->lastItem() ?? 0 }} of {{ number_format($movements->total()) }} movements
</div>
<div class="flex items-center space-x-2">
<span>Per page:</span>
<flux:select wire:model.live="perPage" class="w-20">
<option value="15">15</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</flux:select>
</div>
</div>
<!-- Date To -->
<div>
<flux:input wire:model.live="dateTo" type="date" placeholder="To date" />
</div>
</div>
<div class="mt-4">
<flux:button wire:click="clearFilters" variant="subtle">
Clear Filters
</flux:button>
</div>
</div>
<!-- Movements Table -->
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700 overflow-hidden">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-zinc-200 dark:divide-zinc-700">
<thead class="bg-zinc-50 dark:bg-zinc-900">
<tr>
<th wire:click="sortBy('created_at')" class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider cursor-pointer hover:bg-zinc-100 dark:hover:bg-zinc-800">
<div class="flex items-center space-x-1">
<span>Date</span>
@if($sortBy === 'created_at')
@if($sortDirection === 'asc')
<flux:icon.chevron-up class="w-6 h-6" />
@else
<flux:icon.chevron-down class="w-6 h-6" />
@endif
@endif
</div>
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider">
Part
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider">
Type
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider">
Quantity
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider">
Reference
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider">
User
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider">
Notes
</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-zinc-800 divide-y divide-zinc-200 dark:divide-zinc-700">
@forelse($movements as $movement)
<tr class="hover:bg-zinc-50 dark:hover:bg-zinc-700">
<td class="px-6 py-4 whitespace-nowrap text-sm text-zinc-500 dark:text-zinc-400 dark:text-gray-400">
{{ $movement->created_at->format('M d, Y H:i') }}
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-zinc-900 dark:text-white dark:text-white">{{ $movement->part->name }}</div>
<div class="text-sm text-zinc-500 dark:text-zinc-400 dark:text-gray-400">{{ $movement->part->part_number }}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
@php
$typeColors = [
'in' => 'green',
'out' => 'red',
'adjustment' => 'blue',
'transfer' => 'purple',
'return' => 'orange'
];
@endphp
<flux:badge size="sm" color="{{ $typeColors[$movement->movement_type] ?? 'gray' }}">
{{ ucfirst($movement->movement_type) }}
</flux:badge>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<span class="{{ $movement->movement_type === 'in' ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400' }}">
{{ $movement->movement_type === 'in' ? '+' : '-' }}{{ number_format($movement->quantity) }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-zinc-500 dark:text-zinc-400 dark:text-gray-400">
{{ $movement->reference_type ?? 'Manual' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-zinc-500 dark:text-zinc-400 dark:text-gray-400">
{{ $movement->createdBy->name ?? 'System' }}
</td>
<td class="px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400 dark:text-gray-400 max-w-xs truncate">
{{ $movement->notes }}
</td>
</tr>
@empty
<tr>
<td colspan="7" class="px-6 py-12 text-center">
<div class="text-zinc-500 dark:text-zinc-400 dark:text-gray-400">
<flux:icon.clipboard-document-list class="mx-auto h-12 w-12 mb-4 opacity-40" />
<p class="text-lg font-medium">No stock movements found</p>
<p class="text-sm">Stock movements will appear here as inventory changes occur.</p>
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<!-- Pagination -->
@if($movements->hasPages())
<div class="bg-zinc-50 dark:bg-zinc-900 px-6 py-3 border-t border-zinc-200 dark:border-zinc-700">
{{ $movements->links() }}
</div>
@endif
</div>
</div>