523 lines
21 KiB
PHP
523 lines
21 KiB
PHP
@extends('layouts.winemaker')
|
|
|
|
@section('title', 'Bottle Wine - Winemaker')
|
|
|
|
@section('content')
|
|
<style>
|
|
.page-header {
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.page-title {
|
|
font-size: 2rem;
|
|
font-weight: 700;
|
|
color: #2d3748;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.breadcrumb {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
color: #718096;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.breadcrumb a {
|
|
color: #4a5568;
|
|
text-decoration: none;
|
|
transition: color 0.2s;
|
|
}
|
|
|
|
.breadcrumb a:hover {
|
|
color: #2d3748;
|
|
}
|
|
|
|
.content-layout {
|
|
display: grid;
|
|
grid-template-columns: 1fr 350px;
|
|
gap: 2rem;
|
|
}
|
|
|
|
.content-card {
|
|
background: white;
|
|
border-radius: 12px;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
padding: 2rem;
|
|
}
|
|
|
|
.card-title {
|
|
font-size: 1.25rem;
|
|
font-weight: 600;
|
|
color: #2d3748;
|
|
margin-bottom: 1.5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.form-label {
|
|
display: block;
|
|
font-weight: 500;
|
|
color: #4a5568;
|
|
margin-bottom: 0.5rem;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.form-input,
|
|
.form-select,
|
|
.form-textarea {
|
|
width: 100%;
|
|
padding: 0.75rem 1rem;
|
|
border: 2px solid #e2e8f0;
|
|
border-radius: 8px;
|
|
font-size: 0.875rem;
|
|
transition: all 0.2s;
|
|
font-family: inherit;
|
|
}
|
|
|
|
.form-input:focus,
|
|
.form-select:focus,
|
|
.form-textarea:focus {
|
|
outline: none;
|
|
border-color: #89b4d9;
|
|
box-shadow: 0 0 0 3px rgba(137, 180, 217, 0.1);
|
|
}
|
|
|
|
.form-textarea {
|
|
resize: vertical;
|
|
min-height: 100px;
|
|
}
|
|
|
|
.form-row {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.form-hint {
|
|
font-size: 0.75rem;
|
|
color: #718096;
|
|
margin-top: 0.25rem;
|
|
}
|
|
|
|
.btn-submit {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.5rem;
|
|
width: 100%;
|
|
padding: 0.875rem 1.5rem;
|
|
background: linear-gradient(135deg, #48bb78 0%, #38a169 100%);
|
|
color: white;
|
|
border: none;
|
|
border-radius: 8px;
|
|
font-weight: 600;
|
|
font-size: 1rem;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.btn-submit:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(72, 187, 120, 0.4);
|
|
}
|
|
|
|
.btn-cancel {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.5rem;
|
|
width: 100%;
|
|
padding: 0.875rem 1.5rem;
|
|
background: white;
|
|
color: #4a5568;
|
|
border: 2px solid #e2e8f0;
|
|
border-radius: 8px;
|
|
font-weight: 600;
|
|
font-size: 1rem;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
text-decoration: none;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.btn-cancel:hover {
|
|
background: #f7fafc;
|
|
border-color: #cbd5e0;
|
|
}
|
|
|
|
.harvest-info {
|
|
background: linear-gradient(135deg, #f7fafc 0%, #edf2f7 100%);
|
|
border-radius: 8px;
|
|
padding: 1rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.harvest-info-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 0.5rem 0;
|
|
border-bottom: 1px solid #e2e8f0;
|
|
}
|
|
|
|
.harvest-info-row:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.harvest-info-label {
|
|
font-size: 0.875rem;
|
|
color: #718096;
|
|
}
|
|
|
|
.harvest-info-value {
|
|
font-weight: 600;
|
|
color: #2d3748;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.sidebar-card {
|
|
position: sticky;
|
|
top: 80px;
|
|
}
|
|
|
|
.info-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 0.75rem;
|
|
padding: 1rem;
|
|
background: #f7fafc;
|
|
border-radius: 8px;
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
|
|
.info-icon {
|
|
width: 20px;
|
|
height: 20px;
|
|
color: #89b4d9;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.info-text {
|
|
font-size: 0.875rem;
|
|
color: #4a5568;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.icon {
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
|
|
.error-message {
|
|
color: #dc3545;
|
|
font-size: 0.875rem;
|
|
margin-top: 0.25rem;
|
|
}
|
|
|
|
@media (max-width: 968px) {
|
|
.content-layout {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.sidebar-card {
|
|
position: static;
|
|
}
|
|
|
|
.form-row {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<div class="page-header">
|
|
<div class="breadcrumb">
|
|
<a href="{{ route('winemaker.harvests.index') }}">Harvests</a>
|
|
<svg style="width: 16px; height: 16px;" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
|
|
</svg>
|
|
<span>Bottle Wine</span>
|
|
</div>
|
|
<h1 class="page-title">Bottle Wine from Harvest</h1>
|
|
</div>
|
|
|
|
<div class="content-layout">
|
|
<div class="content-card">
|
|
<h2 class="card-title">
|
|
<svg class="icon" fill="currentColor" viewBox="0 0 24 24">
|
|
<path d="M6,2V10C6,11.11 6.9,12 8,12H10V22H14V12H16C17.11,12 18,11.11 18,10V2H6M8,4H10V6H8V4M12,4H14V6H12V4M16,4H18V6H16V4M8,8H10V10H8V8M12,8H14V10H12V8M16,8H18V10H16V8Z"/>
|
|
</svg>
|
|
Wine Details
|
|
</h2>
|
|
|
|
<div class="harvest-info">
|
|
<h3 style="font-size: 0.875rem; font-weight: 600; color: #4a5568; margin-bottom: 0.75rem; text-transform: uppercase;">Selected Harvest</h3>
|
|
<div class="harvest-info-row">
|
|
<span class="harvest-info-label">Harvest ID:</span>
|
|
<span class="harvest-info-value">#{{ $harvest->id }}</span>
|
|
</div>
|
|
<div class="harvest-info-row">
|
|
<span class="harvest-info-label">Date:</span>
|
|
<span class="harvest-info-value">
|
|
@if($harvest->plannedTask && $harvest->plannedTask->execution_date)
|
|
{{ \Carbon\Carbon::parse($harvest->plannedTask->execution_date)->format('d M Y') }}
|
|
@else
|
|
{{ \Carbon\Carbon::parse($harvest->date)->format('d M Y') }}
|
|
@endif
|
|
</span>
|
|
</div>
|
|
<div class="harvest-info-row">
|
|
<span class="harvest-info-label">Variety:</span>
|
|
<span class="harvest-info-value">{{ $harvest->varietyVariation->grapeVariety->variety_name ?? 'Unknown' }}</span>
|
|
</div>
|
|
<div class="harvest-info-row">
|
|
<span class="harvest-info-label">Total Weight:</span>
|
|
<span class="harvest-info-value">{{ number_format($harvest->weight, 2) }} kg</span>
|
|
</div>
|
|
<div class="harvest-info-row">
|
|
<span class="harvest-info-label">Consumed:</span>
|
|
<span class="harvest-info-value">{{ number_format($harvest->consumed_weight, 2) }} kg</span>
|
|
</div>
|
|
<div class="harvest-info-row">
|
|
<span class="harvest-info-label">Available:</span>
|
|
<span class="harvest-info-value" style="color: {{ $harvest->remaining_weight > 0 ? '#065f46' : '#dc3545' }}; font-weight: 700;">
|
|
{{ number_format($harvest->remaining_weight, 2) }} kg
|
|
</span>
|
|
</div>
|
|
<div class="harvest-info-row">
|
|
<span class="harvest-info-label">Sugar Content:</span>
|
|
<span class="harvest-info-value">{{ number_format($harvest->sugar_content, 1) }}°NM</span>
|
|
</div>
|
|
</div>
|
|
|
|
<form action="{{ route('winemaker.harvests.bottle.store') }}" method="POST" enctype="multipart/form-data">
|
|
@csrf
|
|
<input type="hidden" name="harvest_id" value="{{ $harvest->id }}">
|
|
|
|
<div class="form-group">
|
|
<label for="weight_to_use" class="form-label">Weight to Use (kg) *</label>
|
|
<input type="number" id="weight_to_use" name="weight_to_use" class="form-input"
|
|
value="{{ old('weight_to_use', number_format($harvest->remaining_weight, 2, '.', '')) }}"
|
|
min="0.01"
|
|
max="{{ $harvest->remaining_weight }}"
|
|
step="0.01"
|
|
required>
|
|
<div class="form-hint">Maximum available: {{ number_format($harvest->remaining_weight, 2) }} kg</div>
|
|
@error('weight_to_use')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="wine_name" class="form-label">Wine Name *</label>
|
|
<input type="text" id="wine_name" name="wine_name" class="form-input" value="{{ old('wine_name') }}" required>
|
|
@error('wine_name')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="vintage" class="form-label">Vintage Year *</label>
|
|
@php
|
|
$harvestDate = ($harvest->plannedTask && $harvest->plannedTask->execution_date)
|
|
? $harvest->plannedTask->execution_date
|
|
: $harvest->date;
|
|
@endphp
|
|
<input type="number" id="vintage" name="vintage" class="form-input" value="{{ old('vintage', \Carbon\Carbon::parse($harvestDate)->year) }}" min="1900" max="{{ date('Y') + 1 }}" required>
|
|
@error('vintage')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="wine_type" class="form-label">Wine Type *</label>
|
|
<select id="wine_type" name="wine_type" class="form-select" required>
|
|
<option value="">Select type</option>
|
|
<option value="red" {{ old('wine_type') == 'red' ? 'selected' : '' }}>Red</option>
|
|
<option value="white" {{ old('wine_type') == 'white' ? 'selected' : '' }}>White</option>
|
|
<option value="rose" {{ old('wine_type') == 'rose' ? 'selected' : '' }}>Rosé</option>
|
|
</select>
|
|
@error('wine_type')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="sweetness" class="form-label">Sweetness *</label>
|
|
<select id="sweetness" name="sweetness" class="form-select" required>
|
|
<option value="">Select sweetness</option>
|
|
<option value="dry" {{ old('sweetness') == 'dry' ? 'selected' : '' }}>Dry</option>
|
|
<option value="semi_dry" {{ old('sweetness') == 'semi_dry' ? 'selected' : '' }}>Semi-Dry</option>
|
|
<option value="semi_sweet" {{ old('sweetness') == 'semi_sweet' ? 'selected' : '' }}>Semi-Sweet</option>
|
|
<option value="sweet" {{ old('sweetness') == 'sweet' ? 'selected' : '' }}>Sweet</option>
|
|
</select>
|
|
@error('sweetness')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="alcohol_percentage" class="form-label">Alcohol % *</label>
|
|
<input type="number" id="alcohol_percentage" name="alcohol_percentage" class="form-input" value="{{ old('alcohol_percentage') }}" min="0" max="20" step="0.1" required>
|
|
@error('alcohol_percentage')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="bottles_produced" class="form-label">Bottles Produced *</label>
|
|
<input type="number" id="bottles_produced" name="bottles_produced" class="form-input" value="{{ old('bottles_produced') }}" min="1" required>
|
|
<div class="form-hint">Number of bottles produced</div>
|
|
@error('bottles_produced')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="bottle_volume" class="form-label">Bottle Volume (L)</label>
|
|
<input type="number" id="bottle_volume" name="bottle_volume" class="form-input" value="{{ old('bottle_volume', '0.75') }}" min="0.1" max="10" step="0.01">
|
|
<div class="form-hint">Default: 0.75L</div>
|
|
@error('bottle_volume')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="production_date" class="form-label">Production Date *</label>
|
|
@php
|
|
$harvestDate = ($harvest->plannedTask && $harvest->plannedTask->execution_date)
|
|
? $harvest->plannedTask->execution_date
|
|
: $harvest->date;
|
|
@endphp
|
|
<input type="date" id="production_date" name="production_date" class="form-input" value="{{ old('production_date', \Carbon\Carbon::parse($harvestDate)->format('Y-m-d')) }}" required>
|
|
@error('production_date')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="bottling_date" class="form-label">Bottling Date</label>
|
|
<input type="date" id="bottling_date" name="bottling_date" class="form-input" value="{{ old('bottling_date') }}">
|
|
<div class="form-hint">Leave empty if not yet bottled</div>
|
|
@error('bottling_date')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="status" class="form-label">Wine Status *</label>
|
|
<select id="status" name="status" class="form-select" required>
|
|
<option value="in_production" {{ old('status', 'in_production') == 'in_production' ? 'selected' : '' }}>In Production</option>
|
|
<option value="aging" {{ old('status') == 'aging' ? 'selected' : '' }}>Aging</option>
|
|
<option value="ready" {{ old('status') == 'ready' ? 'selected' : '' }}>Ready</option>
|
|
</select>
|
|
<div class="form-hint">Set to "Ready" if the wine is prepared for sale</div>
|
|
@error('status')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="price_per_bottle" class="form-label">Price per Bottle (€)</label>
|
|
<input type="number" id="price_per_bottle" name="price_per_bottle" class="form-input" value="{{ old('price_per_bottle') }}" min="0" step="0.01">
|
|
<div class="form-hint">Set price now or later</div>
|
|
@error('price_per_bottle')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="description" class="form-label">Description</label>
|
|
<textarea id="description" name="description" class="form-textarea" rows="4">{{ old('description') }}</textarea>
|
|
<div class="form-hint">Tasting notes, characteristics, pairing suggestions</div>
|
|
@error('description')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="image" class="form-label">Wine Image</label>
|
|
<input type="file" id="image" name="image" class="form-input" accept="image/*">
|
|
<div class="form-hint">Upload an image of the wine bottle (JPG, PNG, max 2MB)</div>
|
|
@error('image')
|
|
<div class="error-message">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
|
|
<button type="submit" class="btn-submit">
|
|
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
|
|
</svg>
|
|
Create Wine
|
|
</button>
|
|
|
|
<a href="{{ route('winemaker.harvests.index') }}" class="btn-cancel">
|
|
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
|
|
</svg>
|
|
Cancel
|
|
</a>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="sidebar-card content-card">
|
|
<h3 class="card-title">
|
|
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
|
|
</svg>
|
|
Bottling Guidelines
|
|
</h3>
|
|
|
|
<div class="info-item">
|
|
<svg class="info-icon" fill="currentColor" viewBox="0 0 20 20">
|
|
<path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z"/>
|
|
<path fill-rule="evenodd" d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm3 4a1 1 0 000 2h.01a1 1 0 100-2H7zm3 0a1 1 0 000 2h3a1 1 0 100-2h-3zm-3 4a1 1 0 100 2h.01a1 1 0 100-2H7zm3 0a1 1 0 100 2h3a1 1 0 100-2h-3z" clip-rule="evenodd"/>
|
|
</svg>
|
|
<div class="info-text">
|
|
Fill in all required fields marked with *
|
|
</div>
|
|
</div>
|
|
|
|
<div class="info-item">
|
|
<svg class="info-icon" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd"/>
|
|
</svg>
|
|
<div class="info-text">
|
|
Set status to "Aging" if wine needs to mature before bottling
|
|
</div>
|
|
</div>
|
|
|
|
<div class="info-item">
|
|
<svg class="info-icon" fill="currentColor" viewBox="0 0 20 20">
|
|
<path d="M8.433 7.418c.155-.103.346-.196.567-.267v1.698a2.305 2.305 0 01-.567-.267C8.07 8.34 8 8.114 8 8c0-.114.07-.34.433-.582zM11 12.849v-1.698c.22.071.412.164.567.267.364.243.433.468.433.582 0 .114-.07.34-.433.582a2.305 2.305 0 01-.567.267z"/>
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-13a1 1 0 10-2 0v.092a4.535 4.535 0 00-1.676.662C6.602 6.234 6 7.009 6 8c0 .99.602 1.765 1.324 2.246.48.32 1.054.545 1.676.662v1.941c-.391-.127-.68-.317-.843-.504a1 1 0 10-1.51 1.31c.562.649 1.413 1.076 2.353 1.253V15a1 1 0 102 0v-.092a4.535 4.535 0 001.676-.662C13.398 13.766 14 12.991 14 12c0-.99-.602-1.765-1.324-2.246A4.535 4.535 0 0011 9.092V7.151c.391.127.68.317.843.504a1 1 0 101.511-1.31c-.563-.649-1.413-1.076-2.354-1.253V5z" clip-rule="evenodd"/>
|
|
</svg>
|
|
<div class="info-text">
|
|
Set price now or update it later when ready for sale
|
|
</div>
|
|
</div>
|
|
|
|
<div class="info-item">
|
|
<svg class="info-icon" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd"/>
|
|
</svg>
|
|
<div class="info-text">
|
|
Wine can be linked to this harvest for traceability
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|