UniformFlow/resources/views/issues/index.blade.php

102 lines
6.3 KiB
PHP

@extends('layouts.app')
@section('title', 'Issue uniforms - UniformFlow')
@section('page-heading', 'Issue uniforms')
@section('content')
<section class="page-intro"><div><span class="eyebrow">Employee allocation</span><h1>Issue the <em>correct size.</em></h1><p>Search employees and available uniform sizes without scrolling through long lists.</p></div></section>
<section class="panel issue-form">
<div class="panel-head"><div><span class="eyebrow">New issue</span><h2>Assign a uniform</h2></div></div>
<form method="POST" action="{{ route('issues.store') }}" class="form-grid issue-grid" id="issue-form">@csrf
<label>Employee
<div class="search-select" data-url="{{ route('issues.lookups.employees') }}">
<input type="search" class="search-select-input" autocomplete="off" required placeholder="Search name, employee ID or department" value="{{ $selectedEmployee?->name }}">
<input type="hidden" name="employee_id" value="{{ old('employee_id') }}">
<span class="search-icon"></span><div class="search-results" hidden></div>
</div>
</label>
<label>Uniform and size
<div class="search-select" data-url="{{ route('issues.lookups.variants') }}">
<input type="search" class="search-select-input" autocomplete="off" required placeholder="Search uniform, code or size" value="{{ $selectedVariant ? $selectedVariant->item->name.' / Size '.$selectedVariant->size : '' }}">
<input type="hidden" name="stock_variant_id" value="{{ old('stock_variant_id') }}">
<span class="search-icon"></span><div class="search-results" hidden></div>
</div>
</label>
<label>Quantity<input type="number" min="1" name="quantity" value="{{ old('quantity', 1) }}" required></label>
<label>Issue date<input type="date" name="issued_at" value="{{ old('issued_at', now()->toDateString()) }}" required></label>
<label>Notes<input name="notes" value="{{ old('notes') }}" placeholder="Optional issue note"></label>
<button class="button primary" type="submit">Confirm issue</button>
</form>
</section>
<section class="panel table-panel"><div class="panel-head"><div><span class="eyebrow">Issue register</span><h2>Recent issues</h2></div></div><div class="table-wrap"><table><thead><tr><th>Date</th><th>Employee</th><th>Uniform</th><th>Size</th><th>Qty</th><th>Status</th></tr></thead><tbody>
@forelse($issues as $issue)<tr><td>{{ $issue->issued_at->format('d M Y') }}</td><td><a class="text-link" href="{{ route('employees.show',$issue->employee) }}">{{ $issue->employee->name }}</a><small class="block">{{ $issue->employee->employee_no }}</small></td><td><strong>{{ $issue->variant->item->name }}</strong></td><td><span class="size-badge">{{ $issue->variant->size }}</span></td><td>{{ $issue->quantity }}</td><td><span class="pill {{ $issue->status === 'issued' ? 'warning' : 'good' }}">{{ str_replace('_',' ', ucfirst($issue->status)) }}</span></td></tr>@empty<tr><td colspan="6" class="empty">No issue records yet.</td></tr>@endforelse</tbody></table></div><div class="pagination">{{ $issues->links() }}</div></section>
<script>
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.search-select').forEach(widget => {
const input = widget.querySelector('.search-select-input');
const hidden = widget.querySelector('input[type="hidden"]');
const results = widget.querySelector('.search-results');
let timer;
let requestNumber = 0;
const close = () => { results.hidden = true; };
const search = () => {
const currentRequest = ++requestNumber;
results.hidden = false;
results.innerHTML = '<div class="search-message">Searching...</div>';
fetch(`${widget.dataset.url}?q=${encodeURIComponent(input.value.trim())}`, {headers: {'Accept': 'application/json'}})
.then(response => response.json())
.then(items => {
if (currentRequest !== requestNumber) return;
results.innerHTML = '';
if (!items.length) {
results.innerHTML = '<div class="search-message">No matching records found.</div>';
return;
}
items.forEach(item => {
const button = document.createElement('button');
button.type = 'button';
button.className = 'search-result';
const title = document.createElement('strong');
const subtitle = document.createElement('small');
title.textContent = item.title;
subtitle.textContent = item.subtitle;
button.append(title, subtitle);
button.addEventListener('click', () => {
hidden.value = item.id;
input.value = item.title;
input.setCustomValidity('');
close();
});
results.appendChild(button);
});
})
.catch(() => { results.innerHTML = '<div class="search-message error">Search could not be loaded.</div>'; });
};
input.addEventListener('focus', search);
input.addEventListener('input', () => {
hidden.value = '';
clearTimeout(timer);
timer = setTimeout(search, 220);
});
input.addEventListener('keydown', event => { if (event.key === 'Escape') close(); });
document.addEventListener('click', event => { if (!widget.contains(event.target)) close(); });
});
document.getElementById('issue-form').addEventListener('submit', event => {
document.querySelectorAll('.search-select').forEach(widget => {
const input = widget.querySelector('.search-select-input');
const hidden = widget.querySelector('input[type="hidden"]');
if (!hidden.value) {
event.preventDefault();
input.setCustomValidity('Choose a record from the search results.');
input.reportValidity();
}
});
});
});
</script>
@endsection