102 lines
6.3 KiB
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
|