yoco updated to use webhook
This commit is contained in:
@@ -0,0 +1,420 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Order #' . $order->order_number . ' - Order Details')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
/* Page-specific typography overrides */
|
||||
h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.6rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.page-intro {
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.page-intro p {
|
||||
color: var(--text-secondary);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Card styles */
|
||||
.card {
|
||||
padding: var(--spacing-lg);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-section {
|
||||
margin-bottom: var(--spacing-lg);
|
||||
padding-bottom: var(--spacing-lg);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.card-section:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.content-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr;
|
||||
gap: var(--spacing-lg);
|
||||
}
|
||||
|
||||
/* Order items styling */
|
||||
.order-item {
|
||||
padding: var(--spacing-md);
|
||||
background-color: white;
|
||||
border-radius: 20px;
|
||||
margin-bottom: var(--spacing-md);
|
||||
border: 1px solid var(--border-color);
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.order-item:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.item-price {
|
||||
font-weight: 700;
|
||||
color: var(--accent-dark);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Payment action styling */
|
||||
.payment-action-box {
|
||||
padding: var(--spacing-lg);
|
||||
border-radius: 20px;
|
||||
margin-top: var(--spacing-lg);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.payment-action-box.pending {
|
||||
background-color: var(--accent-light);
|
||||
border: 2px solid var(--accent-dark);
|
||||
}
|
||||
|
||||
.payment-action-box.failed {
|
||||
background-color: var(--accent-light);
|
||||
border: 2px solid var(--accent-dark);
|
||||
}
|
||||
|
||||
.payment-action-box.success {
|
||||
background-color: var(--accent-light);
|
||||
border: 2px solid var(--accent-dark);
|
||||
}
|
||||
|
||||
.payment-amount {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.payment-amount-label {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.payment-amount-value {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.pending .payment-amount-value {
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.failed .payment-amount-value {
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.success .payment-amount-value {
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 1rem 2rem;
|
||||
background-color: var(--accent-dark);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 20px;
|
||||
font-weight: 600;
|
||||
transition: var(--transition);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: var(--accent-pink);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-pending {var(--accent-dark);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-failed {
|
||||
background-color: var(--accent-dark)
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.success-check {
|
||||
font-sivar(--accent-dark)m;
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 0.4rem 0.8rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.status-badge.paid {var(--accent-light);
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.status-badge.pending {
|
||||
background-color: var(--accent-light);
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.status-badge.failed {
|
||||
background-color: var(--accent-light);
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.status-badge.processing {
|
||||
background-color: var(--accent-light);
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.status-badge.shipped {
|
||||
background-color: var(--accent-light);
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.status-badge.delivered {
|
||||
background-color: var(--accent-light);
|
||||
color: var(--accent-dark)or: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.content-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.payment-action-box {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.payment-amount {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="page-intro">
|
||||
<h1>Order Details</h1>
|
||||
<p>Order #{{ $order->order_number }}</p>
|
||||
</div>
|
||||
|
||||
<div class="content-grid">
|
||||
<!-- Main Content -->
|
||||
<div>
|
||||
<!-- Order Status -->
|
||||
<div class="card">
|
||||
<h2>Order Status</h2>
|
||||
<div class="card-section">
|
||||
<span class="status-badge {{ $order->status }}">
|
||||
{{ str_replace('_', ' ', ucfirst($order->status)) }}
|
||||
</span>
|
||||
<p style="margin-top: var(--spacing-sm); color: var(--text-secondary); font-size: 0.9rem;">
|
||||
Ordered on {{ $order->created_at->format('d M Y \a\t H:i') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Items -->
|
||||
<div class="card">
|
||||
<h2>Order Items</h2>
|
||||
@foreach($order->items as $item)
|
||||
<div class="order-item">
|
||||
<div class="item-header">
|
||||
<div>
|
||||
<div class="item-name">{{ $item->product->name }}</div>
|
||||
<div class="item-meta">{{ $item->type }}</div>
|
||||
@if($item->length)
|
||||
<div class="item-meta">Length: {{ $item->length }}m</div>
|
||||
@endif
|
||||
@if($item->width && $item->height)
|
||||
<div class="item-meta">Dimensions: {{ $item->width }}m × {{ $item->height }}m</div>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
<div class="item-price">R {{ number_format($item->price, 2) }}</div>
|
||||
<div class="item-meta" style="text-align: right;">Qty: {{ $item->quantity }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<!-- Shipping Details -->
|
||||
<div class="card">
|
||||
<h2>Delivery Details</h2>
|
||||
|
||||
<div class="card-section">
|
||||
<h3>Customer Information</h3>
|
||||
<dl style="color: var(--text-secondary);">
|
||||
<div class="spec-group">
|
||||
<dt>Name:</dt>
|
||||
<dd>{{ $order->customer_name }}</dd>
|
||||
</div>
|
||||
<div class="spec-group">
|
||||
<dt>Email:</dt>
|
||||
<dd>{{ $order->customer_email }}</dd>
|
||||
</div>
|
||||
<div class="spec-group">
|
||||
<dt>Phone:</dt>
|
||||
<dd>{{ $order->customer_phone }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="card-section">
|
||||
<h3>Shipping Address</h3>
|
||||
<p style="color: var(--text-secondary); line-height: 1.6;">{{ $order->shipping_address }}</p>
|
||||
</div>
|
||||
|
||||
@if($order->notes)
|
||||
<div class="card-section">
|
||||
<h3>Order Notes</h3>
|
||||
<p style="color: var(--text-secondary);">{{ $order->notes }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div>
|
||||
<!-- Order Summary & Payment -->
|
||||
<div class="card">
|
||||
<h2>Order Summary</h2>
|
||||
|
||||
<div class="card-section">
|
||||
<div class="payment-row" style="display: flex; justify-content: space-between; margin-bottom: var(--spacing-sm); color: var(--text-secondary);">
|
||||
<span>Subtotal:</span>
|
||||
<span>R {{ number_format($order->total, 2) }}</span>
|
||||
</div>
|
||||
<div class="payment-row total" style="display: flex; justify-content: space-between; border-top: 2px solid var(--border-color); padding-top: var(--spacing-md); font-weight: 700; font-size: 1.2rem;">
|
||||
<span>Total:</span>
|
||||
<span>R {{ number_format($order->total, 2) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 style="margin-top: var(--spacing-lg); margin-bottom: var(--spacing-md);">Payment Status</h3>
|
||||
|
||||
<div style="padding: var(--spacing-sm); background-color: var(--accent-light); border-radius: 20px; margin-bottom: var(--spacing-lg);">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<strong>Payment</strong>
|
||||
<span class="status-badge {{ $order->payment_status }}">{{ ucfirst($order->payment_status) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Payment Actions -->
|
||||
@if($order->payment_status === 'pending' && $order->yoco_redirect_url)
|
||||
<div class="payment-action-box pending">
|
||||
<div>
|
||||
<h3 style="margin-top: 0; color: var(--accent-dark);">Payment Required</h3>
|
||||
<p style="color: var(--accent-dark); margin: var(--spacing-sm) 0 0 0;">Click below to complete your payment.</p>
|
||||
<a href="{{ $order->yoco_redirect_url }}"
|
||||
target="_blank"
|
||||
class="btn btn-pending"
|
||||
style="margin-top: var(--spacing-md);">
|
||||
Pay Now
|
||||
</a>
|
||||
</div>
|
||||
<div class="payment-amount">
|
||||
<div class="payment-amount-label">Amount Due</div>
|
||||
<div class="payment-amount-value">R {{ number_format($order->total, 2) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@elseif($order->payment_status === 'failed' && $order->yoco_redirect_url)
|
||||
<div class="payment-action-box failed">
|
||||
<div>
|
||||
<h3 style="margin-top: 0; color: var(--accent-dark);">Payment Failed</h3>
|
||||
<p style="color: var(--accent-dark); margin: var(--spacing-sm) 0 0 0;">Please try your payment again.</p>
|
||||
<a href="{{ $order->yoco_redirect_url }}"
|
||||
target="_blank"
|
||||
class="btn btn-failed"
|
||||
style="margin-top: var(--spacing-md);">
|
||||
Retry Payment
|
||||
</a>
|
||||
</div>
|
||||
<div class="payment-amount">
|
||||
<div class="payment-amount-label">Amount Due</div>
|
||||
<div class="payment-amount-value">R {{ number_format($order->total, 2) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@elseif($order->payment_status === 'paid')
|
||||
<div class="payment-action-box success">
|
||||
<div style="display: flex; gap: var(--spacing-md); align-items: flex-start;">
|
||||
<div class="success-check">✓</div>
|
||||
<div>
|
||||
<h3 style="margin-top: 0; color: var(--accent-dark);">Payment Received</h3>
|
||||
<p style="color: var(--accent-dark); margin: var(--spacing-sm) 0 0 0; font-size: 0.9rem;">Thank you! Your order is being processed.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Back Link -->
|
||||
<div style="text-align: center; margin-top: var(--spacing-lg);">
|
||||
<a href="{{ route('my-orders') }}" style="color: var(--accent-dark); text-decoration: none; font-weight: 600;">
|
||||
← Back to Orders
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,277 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'My Orders - Additional Design')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.8rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.page-intro {
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.page-intro p {
|
||||
color: var(--text-secondary);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.orders-section {
|
||||
margin-bottom: var(--spacing-xl);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.btn-new {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.btn-new {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.table-container {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
thead {
|
||||
background-color: var(--bg-secondary);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
th {
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
background-color: var(--bg-primary);
|
||||
}
|
||||
|
||||
td {
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
font-size: 0.95rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.order-number {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 0.35rem 0.75rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-view {
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.btn-view:hover {
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
background-color: var(--bg-secondary);
|
||||
border-radius: 8px;
|
||||
padding: var(--spacing-xl);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
font-size: 1.05rem;
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.empty-state a {
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
padding: var(--spacing-sm) var(--spacing-lg);
|
||||
background-color: var(--accent-dark);
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.empty-state a:hover {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
table {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: var(--spacing-xs) var(--spacing-sm);
|
||||
}
|
||||
|
||||
.btn-new {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="page-intro">
|
||||
<h1>My Orders</h1>
|
||||
<p>View your standard and custom orders</p>
|
||||
</div>
|
||||
|
||||
<!-- Standard Orders -->
|
||||
<div class="orders-section">
|
||||
<h2>Standard Orders</h2>
|
||||
|
||||
@if ($standardOrders->count() > 0)
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order #</th>
|
||||
<th>Date</th>
|
||||
<th>Total</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($standardOrders as $order)
|
||||
<tr>
|
||||
<td class="order-number">{{ $order->order_number }}</td>
|
||||
<td>{{ $order->created_at->format('d M Y') }}</td>
|
||||
<td><strong>R{{ number_format($order->total, 2) }}</strong></td>
|
||||
<td>
|
||||
<span class="status-badge {{ $order->status }}">
|
||||
{{ ucfirst(str_replace('_', ' ', $order->status)) }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('my-orders.detail', $order) }}" class="btn-view">View Details</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
<div class="empty-state">
|
||||
<p>You haven't placed any standard orders yet.</p>
|
||||
<a href="{{ route('wallpapers') }}">Browse Products</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Custom Orders -->
|
||||
<div class="orders-section">
|
||||
<div class="section-header">
|
||||
<h2 style="margin-bottom: 0;">Custom Orders</h2>
|
||||
<a href="{{ route('custom-orders.create') }}" class="btn btn-new">+ New Custom Order</a>
|
||||
</div>
|
||||
|
||||
@if ($customOrders->count() > 0)
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order #</th>
|
||||
<th>Type</th>
|
||||
<th>Total</th>
|
||||
<th>Status</th>
|
||||
<th>Deposit</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($customOrders as $order)
|
||||
<tr>
|
||||
<td class="order-number">{{ $order->order_number }}</td>
|
||||
<td class="capitalize">{{ ucfirst($order->type) }}</td>
|
||||
<td><strong>R{{ number_format($order->total_cost, 2) }}</strong></td>
|
||||
<td>
|
||||
<span class="status-badge {{ $order->status }}">
|
||||
{{ str_replace('_', ' ', ucfirst($order->status)) }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="status-badge {{ $order->deposit_status }}">
|
||||
{{ ucfirst($order->deposit_status) }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('custom-orders.show', $order) }}" class="btn-view">View Details</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
<div class="empty-state">
|
||||
<p>You haven't created any custom orders yet.</p>
|
||||
<a href="{{ route('custom-orders.create') }}">Create Custom Order</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,94 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<h1 class="text-3xl font-bold mb-8">Pending Payments</h1>
|
||||
|
||||
@if($orders->isEmpty())
|
||||
<div class="bg-blue-50 border border-blue-200 rounded-lg p-6">
|
||||
<p class="text-blue-800">You have no pending payments. All your orders are either paid or cancelled.</p>
|
||||
<a href="{{ route('order-history') }}" class="mt-4 inline-block text-blue-600 hover:text-blue-800 font-semibold">
|
||||
← Back to Order History
|
||||
</a>
|
||||
</div>
|
||||
@else
|
||||
<div class="space-y-4">
|
||||
@foreach($orders as $order)
|
||||
<div class="border border-gray-200 rounded-lg p-6 hover:shadow-lg transition-shadow">
|
||||
<div class="flex justify-between items-start mb-4">
|
||||
<div>
|
||||
<h2 class="text-xl font-semibold text-gray-900">{{ $order->order_number }}</h2>
|
||||
<p class="text-sm text-gray-600">
|
||||
Ordered: {{ $order->created_at->format('M d, Y @ H:i') }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<p class="text-2xl font-bold text-gray-900">R {{ number_format($order->total, 2) }}</p>
|
||||
<span class="inline-block mt-2 px-3 py-1 bg-yellow-100 text-yellow-800 text-xs font-semibold rounded-full">
|
||||
@if($order->payment_status === 'pending')
|
||||
Payment Pending
|
||||
@elseif($order->payment_status === 'failed')
|
||||
Payment Failed
|
||||
@else
|
||||
{{ ucfirst($order->payment_status) }}
|
||||
@endif
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-50 rounded p-4 mb-4">
|
||||
<h3 class="font-semibold text-gray-900 mb-3">Order Items</h3>
|
||||
<div class="space-y-2">
|
||||
@foreach($order->items as $item)
|
||||
<div class="flex justify-between text-sm text-gray-700">
|
||||
<span>{{ $item->product->name }}</span>
|
||||
<span>{{ $item->quantity }} x R {{ number_format($item->price, 2) }}</span>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 text-sm mb-4 pb-4 border-b border-gray-200">
|
||||
<div>
|
||||
<p class="text-gray-600">Customer Name</p>
|
||||
<p class="font-semibold text-gray-900">{{ $order->customer_name }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-600">Shipping Address</p>
|
||||
<p class="font-semibold text-gray-900">{{ $order->shipping_address }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($order->yoco_redirect_url)
|
||||
<div class="flex gap-3">
|
||||
<a href="{{ $order->yoco_redirect_url }}"
|
||||
target="_blank"
|
||||
class="flex-1 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-4 rounded-lg text-center transition-colors">
|
||||
Complete Payment with Yoco
|
||||
</a>
|
||||
<a href="{{ route('order-history') }}"
|
||||
class="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 font-semibold py-3 px-4 rounded-lg text-center transition-colors">
|
||||
Back
|
||||
</a>
|
||||
</div>
|
||||
@else
|
||||
<div class="bg-red-50 border border-red-200 rounded p-4">
|
||||
<p class="text-red-800 text-sm">
|
||||
<strong>Note:</strong> Payment link is not available for this order. Please contact support.
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<a href="{{ route('order-history') }}" class="text-blue-600 hover:text-blue-800 font-semibold">
|
||||
← Back to All Orders
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,275 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'My Account - Additional Design')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.page-intro {
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.page-intro p {
|
||||
color: var(--text-secondary);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.account-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr;
|
||||
gap: var(--spacing-lg);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: white;
|
||||
padding: var(--spacing-lg);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.8rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 1.3rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group textarea {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
font-family: inherit;
|
||||
background-color: var(--bg-primary);
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--text-primary);
|
||||
box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.account-type {
|
||||
padding: var(--spacing-sm) 0;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 0.4rem 1rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.badge-admin {
|
||||
background-color: var(--accent-pink);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.badge-customer {
|
||||
background-color: var(--accent-light);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.sidebar-card {
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.sidebar-card ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sidebar-card li {
|
||||
padding: 0.75rem 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.sidebar-card li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.sidebar-card a {
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.sidebar-card a:hover {
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.help-box {
|
||||
background-color: var(--accent-light);
|
||||
padding: var(--spacing-lg);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.help-box h3 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.help-box p {
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.help-box a {
|
||||
font-weight: 600;
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: var(--spacing-sm);
|
||||
border-radius: 4px;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #e8f5e9;
|
||||
border: 1px solid #c8e6c9;
|
||||
color: #2e7d32;
|
||||
}
|
||||
|
||||
.btn-logout {
|
||||
color: #c53030;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.btn-logout:hover {
|
||||
color: #a02424;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.account-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="page-intro">
|
||||
<h1>My Account</h1>
|
||||
<p>Manage your profile and view your orders</p>
|
||||
</div>
|
||||
|
||||
@if (session('success'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="account-grid">
|
||||
<!-- Profile Section -->
|
||||
<div>
|
||||
<div class="card">
|
||||
<h2>Profile Information</h2>
|
||||
|
||||
<form action="{{ route('my-account.update') }}" method="POST">
|
||||
@csrf
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" id="name" name="name" value="{{ auth()->user()->name }}" required>
|
||||
@error('name')
|
||||
<p style="color: #c53030; font-size: 0.9rem; margin-top: 0.25rem;">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" id="email" name="email" value="{{ auth()->user()->email }}" required>
|
||||
@error('email')
|
||||
<p style="color: #c53030; font-size: 0.9rem; margin-top: 0.25rem;">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group account-type">
|
||||
<label>Account Type</label>
|
||||
@if (auth()->user()->is_admin)
|
||||
<span class="badge badge-admin">Admin</span>
|
||||
@else
|
||||
<span class="badge badge-customer">Customer</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn">Update Profile</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div>
|
||||
<div class="card sidebar-card">
|
||||
<h3>Quick Links</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="{{ route('my-orders') }}">📦 My Orders</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('custom-orders.create') }}">➕ New Custom Order</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="help-box">
|
||||
<h3>Need Help?</h3>
|
||||
<p>Contact us for assistance with your account or orders.</p>
|
||||
<a href="mailto:support@example.com">support@example.com</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; padding: var(--spacing-lg) 0; border-top: 1px solid var(--border-color);">
|
||||
<form action="{{ route('logout') }}" method="POST" style="display: inline;">
|
||||
@csrf
|
||||
<button type="submit" class="btn-logout">Sign Out</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,187 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Sign In - Additional Design')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 70vh;
|
||||
padding: var(--spacing-lg) 0;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
background: white;
|
||||
padding: 3rem;
|
||||
border-radius: 20px;
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.login-card p {
|
||||
text-align: center;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.btn-google {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--spacing-sm);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
background-color: white;
|
||||
border: 2px solid var(--border-color);
|
||||
color: var(--text-primary);
|
||||
border-radius: 50px;
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
transition: var(--transition);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.btn-google:hover {
|
||||
background-color: var(--bg-secondary);
|
||||
border-color: var(--text-primary);
|
||||
}
|
||||
|
||||
.btn-google svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
margin: var(--spacing-lg) 0;
|
||||
}
|
||||
|
||||
.divider-line {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background-color: var(--border-color);
|
||||
}
|
||||
|
||||
.divider-text {
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.btn-guest {
|
||||
width: 100%;
|
||||
display: block;
|
||||
text-align: center;
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
background-color: var(--bg-secondary);
|
||||
color: var(--text-primary);
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
transition: var(--transition);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn-guest:hover {
|
||||
background-color: var(--border-color);
|
||||
}
|
||||
|
||||
.terms {
|
||||
margin-top: var(--spacing-lg);
|
||||
padding-top: var(--spacing-lg);
|
||||
border-top: 1px solid var(--border-color);
|
||||
text-align: center;
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.terms a {
|
||||
color: var(--accent-dark);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: var(--spacing-sm);
|
||||
border-radius: 4px;
|
||||
margin-bottom: var(--spacing-md);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: #fce8e8;
|
||||
border: 1px solid #f5c6cb;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.login-card {
|
||||
padding: 2rem;
|
||||
margin: 0 var(--spacing-md);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="login-container">
|
||||
<div class="login-card">
|
||||
<h1>Sign In</h1>
|
||||
<p>Create an account or continue as guest to access your orders and custom designs</p>
|
||||
|
||||
@if (session('error'))
|
||||
<div class="alert alert-error">
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-error">
|
||||
{{ $errors->first() }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<a href="{{ route('auth.google') }}" class="btn-google">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
||||
<path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
||||
<path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
||||
<path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
||||
</svg>
|
||||
Sign in with Google
|
||||
</a>
|
||||
|
||||
<div class="divider">
|
||||
<div class="divider-line"></div>
|
||||
<span class="divider-text">or</span>
|
||||
<div class="divider-line"></div>
|
||||
</div>
|
||||
|
||||
<a href="{{ route('home') }}" class="btn-guest">
|
||||
Continue as Guest
|
||||
</a>
|
||||
|
||||
<div class="terms">
|
||||
By signing in, you agree to our <a href="#">Terms of Service</a> and <a href="#">Privacy Policy</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -6,27 +6,82 @@
|
||||
<!-- <a href="/">Home</a> -->
|
||||
<a href="/wallpapers">Wallpaper</a>
|
||||
<a href="/murals">Murals</a>
|
||||
<a href="/fabrics">Fabrics</a>
|
||||
<a href="/#portfolio">Portfolio</a>
|
||||
<!-- <a href="/fabrics">Fabrics</a> -->
|
||||
<!-- <a href="/#portfolio">Portfolio</a> -->
|
||||
<a href="/#projects">Projects</a>
|
||||
<!-- <a href="/#shop">Decor Shop</a> -->
|
||||
<a href="/#contact">Contact</a>
|
||||
</nav>
|
||||
<a href="{{ route('cart') }}" style="display: flex; align-items: center; gap: 0.5rem; text-decoration: none; color: inherit; font-weight: 500; position: relative;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="9" cy="21" r="1"></circle>
|
||||
<circle cx="20" cy="21" r="1"></circle>
|
||||
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
|
||||
</svg>
|
||||
<span>Cart</span>
|
||||
@if($cartCount > 0)
|
||||
<span style="background: var(--accent-dark); color: white; border-radius: 50%; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: bold; position: absolute; top: -8px; right: -8px;">{{ $cartCount }}</span>
|
||||
@endif
|
||||
</a>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</button>
|
||||
<div style="display: flex; align-items: center; gap: 1.5rem;">
|
||||
<!-- Authentication Links -->
|
||||
@auth
|
||||
<a href="{{ route('custom-orders.create') }}" style="text-decoration: none; color: inherit; font-weight: 500; font-size: 0.9rem;">Custom Order</a>
|
||||
<div style="position: relative; display: inline-block;">
|
||||
<button onclick="toggleUserMenu()" style="background: none; border: none; cursor: pointer; padding: 0; font-weight: 500; display: flex; align-items: center; gap: 0.5rem; color: inherit; font-size: 0.9rem; font-family: Montserrat, sans-serif;">
|
||||
{{ auth()->user()->name }}
|
||||
<svg style="width: 16px; height: 16px;" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
<div id="user-menu" style="display: none; position: absolute; right: 0; top: 100%; margin-top: 0.5rem; background: white; border-radius: 0.5rem; box-shadow: 0 10px 25px rgba(0,0,0,0.1); min-width: 200px; z-index: 1000;">
|
||||
<a href="{{ route('my-account') }}" style="display: block; padding: 0.75rem 1rem; text-decoration: none; color: inherit; border-bottom: 1px solid #e5e7eb;">My Account</a>
|
||||
<a href="{{ route('my-orders') }}" style="display: block; padding: 0.75rem 1rem; text-decoration: none; color: inherit; border-bottom: 1px solid #e5e7eb;">My Orders</a>
|
||||
@if(auth()->user()->is_admin)
|
||||
<a href="/admin" style="display: block; padding: 0.75rem 1rem; text-decoration: none; color: inherit; border-bottom: 1px solid #e5e7eb;">Admin Panel</a>
|
||||
@endif
|
||||
<form action="{{ route('logout') }}" method="POST" style="margin: 0;" id="logout-form">
|
||||
@csrf
|
||||
<button type="submit" style="font-family: Montserrat, sans-serif; width: 100%; text-align: left; padding: 0.75rem 1rem; background: none; border: none; cursor: pointer; color: inherit; font-weight: 500; font-size: 0.9rem;">Sign Out</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<a href="{{ route('auth.login') }}" style="text-decoration: none; color: inherit; font-weight: 500; font-size: 0.9rem;">Sign In</a>
|
||||
@endauth
|
||||
|
||||
<!-- Cart -->
|
||||
<a href="{{ route('cart') }}" style="display: flex; align-items: center; gap: 0.5rem; text-decoration: none; color: inherit; font-weight: 500; position: relative;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="9" cy="21" r="1"></circle>
|
||||
<circle cx="20" cy="21" r="1"></circle>
|
||||
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
|
||||
</svg>
|
||||
<span>Cart</span>
|
||||
@if($cartCount > 0)
|
||||
<span style="background: var(--accent-dark); color: white; border-radius: 50%; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: bold; position: absolute; top: -8px; right: -8px;">{{ $cartCount }}</span>
|
||||
@endif
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<script>
|
||||
function toggleUserMenu() {
|
||||
const menu = document.getElementById('user-menu');
|
||||
if (menu) {
|
||||
menu.style.display = menu.style.display === 'none' ? 'block' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Close menu when clicking outside
|
||||
document.addEventListener('click', function(event) {
|
||||
const userMenu = document.getElementById('user-menu');
|
||||
const toggleButton = event.target.closest('button[onclick="toggleUserMenu()"]');
|
||||
const logoutForm = document.getElementById('logout-form');
|
||||
|
||||
// Don't close if clicking logout form or the toggle button
|
||||
if (userMenu && !event.target.closest('#user-menu') && !toggleButton && !logoutForm?.contains(event.target)) {
|
||||
userMenu.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Allow logout form to submit by not preventing default
|
||||
document.addEventListener('submit', function(event) {
|
||||
if (event.target.id === 'logout-form') {
|
||||
// Allow normal form submission
|
||||
return true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,749 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Request Custom Design - Additional Design')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
.page-intro {
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.page-intro h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.page-intro p {
|
||||
color: var(--text-secondary);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.form-card {
|
||||
background: white;
|
||||
padding: var(--spacing-lg);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
.form-section h2 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.6rem;
|
||||
color: var(--text-primary);
|
||||
/* margin-bottom: var(--spacing-md); */
|
||||
}
|
||||
|
||||
.form-section {
|
||||
/* margin-bottom: var(--spacing-lg); */
|
||||
}
|
||||
|
||||
.form-section:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.form-group-hint {
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.form-row.full {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group textarea,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
font-family: inherit;
|
||||
background-color: white;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group textarea:focus,
|
||||
.form-group select:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent-dark);
|
||||
box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
resize: vertical;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
border: 2px dashed var(--border-color);
|
||||
border-radius: 8px;
|
||||
padding: var(--spacing-lg);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: var(--transition);
|
||||
background-color: var(--bg-primary);
|
||||
}
|
||||
|
||||
.upload-area:hover {
|
||||
border-color: var(--accent-dark);
|
||||
background-color: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.upload-area svg {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
color: var(--text-secondary);
|
||||
margin: 0 auto var(--spacing-sm);
|
||||
}
|
||||
|
||||
.upload-area p {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
.upload-area .hint {
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem;
|
||||
background-color: var(--bg-secondary);
|
||||
border-radius: 4px;
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.file-item svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: var(--accent-dark);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
padding: var(--spacing-md);
|
||||
background-color: var(--bg-secondary);
|
||||
border-radius: 20px;
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.checkbox-option {
|
||||
display: flex;
|
||||
gap: var(--spacing-md);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-option input[type="checkbox"] {
|
||||
margin-top: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-content p {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: var(--spacing-md);
|
||||
margin-top: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.button-group .btn {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
background-color: var(--bg-secondary) !important;
|
||||
color: var(--text-primary) !important;
|
||||
border: 1px solid var(--border-color) !important;
|
||||
}
|
||||
|
||||
.btn-cancel:hover {
|
||||
background-color: var(--border-color) !important;
|
||||
color: var(--text-primary) !important;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #c53030;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background-color: var(--accent-light);
|
||||
border: 1px solid var(--border-color);
|
||||
padding: var(--spacing-lg);
|
||||
border-radius: 20px;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.info-box h3 {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.info-box ul {
|
||||
list-style-position: inside;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.info-box li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 450px;
|
||||
gap: var(--spacing-lg);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
.cost-summary {
|
||||
height: fit-content;
|
||||
position: sticky;
|
||||
top: 120px;
|
||||
}
|
||||
.cost-summary-content {
|
||||
background: white;
|
||||
padding: var(--spacing-lg);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: var(--spacing-md);
|
||||
|
||||
}
|
||||
|
||||
.cost-summary-content h3 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.3rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.cost-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: var(--spacing-sm) 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.cost-item.total {
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
border-top: 2px solid var(--accent-dark);
|
||||
border-bottom: none;
|
||||
margin-top: var(--spacing-md);
|
||||
padding-top: var(--spacing-md);
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.cost-label {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.cost-value {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.cost-item.total .cost-value {
|
||||
color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.design-fee-note {
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-secondary);
|
||||
margin-top: var(--spacing-md);
|
||||
padding-top: var(--spacing-md);
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.cost-item.disabled {
|
||||
opacity: 0.5;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.cost-item.discount {
|
||||
color: var(--accent-pink);
|
||||
}
|
||||
|
||||
.cost-item.discount .cost-value {
|
||||
color: var(--accent-pink);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.form-wrapper {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.cost-summary-content {
|
||||
position: static;
|
||||
}
|
||||
|
||||
.form-card {
|
||||
padding: var(--spacing-md);
|
||||
}
|
||||
|
||||
.form-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container" style="padding:20px;">
|
||||
<div class="page-intro">
|
||||
<h1>Request Custom Design</h1>
|
||||
<p>Create a custom wallpaper, mural, or fabric design tailored to your needs</p>
|
||||
</div>
|
||||
|
||||
@if ($errors->any())
|
||||
<div style="background-color: #f8d7da; border: 1px solid var(--border-color); color: var(--text-primary); padding: var(--spacing-md); border-radius: 8px; margin-bottom: var(--spacing-lg);">
|
||||
<h4 style="margin-top: 0;">Please correct the following errors:</h4>
|
||||
<ul>
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (session('success'))
|
||||
<div style="background-color: var(--accent-light); border: 1px solid var(--border-color); color: var(--text-primary); padding: var(--spacing-md); border-radius: 8px; margin-bottom: var(--spacing-lg);">
|
||||
✓ {{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Info Box -->
|
||||
<div class="info-box">
|
||||
<h2>How It Works</h2>
|
||||
<ul>
|
||||
<li>Submit your custom order with design specifications and reference images</li>
|
||||
<li>Pay a 20% non-refundable deposit to commence design work</li>
|
||||
<li>Our team creates your design and prepares proofs for review</li>
|
||||
<li>Pay the remaining 80% balance to proceed with printing and shipping</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Form -->
|
||||
<div class="form-wrapper">
|
||||
<form action="{{ route('custom-orders.store') }}" method="POST" enctype="multipart/form-data" id="custom-order-form" class="form-card" data-action="{{ route('custom-orders.store') }}">
|
||||
@csrf
|
||||
|
||||
<!-- Order Type & Dimensions -->
|
||||
<div class="form-section">
|
||||
<h2>Order Details</h2>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="type">Order Type *</label>
|
||||
<select id="type" name="type" required>
|
||||
<option value="">-- Select a type --</option>
|
||||
<option value="wallpaper" {{ old('type') == 'wallpaper' ? 'selected' : '' }}>Wallpaper (tileable pattern)</option>
|
||||
<option value="mural" {{ old('type') == 'mural' ? 'selected' : '' }}>Mural (large format)</option>
|
||||
<option value="fabric" {{ old('type') == 'fabric' ? 'selected' : '' }}>Fabric (linear meter)</option>
|
||||
</select>
|
||||
@error('type')
|
||||
<p class="error-message">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="width">Width (meters) *</label>
|
||||
<input type="number" id="width" name="width" step="0.01" min="0.1" value="{{ old('width') }}" required>
|
||||
@error('width')
|
||||
<p class="error-message">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="height">Height (meters) *</label>
|
||||
<input type="number" id="height" name="height" step="0.01" min="0.1" value="{{ old('height') }}" required>
|
||||
@error('height')
|
||||
<p class="error-message">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="quantity">Quantity *</label>
|
||||
<input type="number" id="quantity" name="quantity" value="{{ old('quantity', 1) }}" min="1" required>
|
||||
@error('quantity')
|
||||
<p class="error-message">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="print_stock_id">Print Material *</label>
|
||||
<select id="print_stock_id" name="print_stock_id" required>
|
||||
<option value="">-- Select material --</option>
|
||||
@foreach ($printStocks as $stock)
|
||||
<option value="{{ $stock->id }}" {{ old('print_stock_id') == $stock->id ? 'selected' : '' }}>
|
||||
{{ $stock->name }} ({{ $stock->cost_per_meter ? 'R' . number_format($stock->cost_per_meter, 2) . '/m' : 'R' . number_format($stock->cost_per_m2, 2) . '/m²' }})
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('print_stock_id')
|
||||
<p class="error-message">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Design Brief -->
|
||||
<div class="form-section">
|
||||
<h2>Design Brief</h2>
|
||||
|
||||
<div class="form-group form-row full">
|
||||
<label for="customer_brief">Design Brief (minimum 50 characters) *</label>
|
||||
<p class="form-group-hint">Tell us about your design concept, colors, style, and any specific requirements</p>
|
||||
<textarea id="customer_brief" name="customer_brief" placeholder="Describe your custom design vision..." minlength="50" required>{{ old('customer_brief') }}</textarea>
|
||||
@error('customer_brief')
|
||||
<p class="error-message">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group form-row full">
|
||||
<label for="special_instructions">Special Instructions (optional)</label>
|
||||
<textarea id="special_instructions" name="special_instructions" placeholder="Any additional notes or requirements...">{{ old('special_instructions') }}</textarea>
|
||||
@error('special_instructions')
|
||||
<p class="error-message">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reference Images -->
|
||||
<div class="form-section">
|
||||
<h2>Reference Images</h2>
|
||||
|
||||
<div class="form-group form-row full">
|
||||
<label>Upload Reference Images</label>
|
||||
<p class="form-group-hint">Upload inspiration images, mood boards, or reference materials for your design</p>
|
||||
<div class="upload-area" onclick="document.getElementById('reference-images').click()">
|
||||
<input type="file" id="reference-images" name="reference_images[]" multiple accept="image/*" style="display: none;">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 48 48">
|
||||
<path d="M28 8H12a4 4 0 00-4 4v20m32-12v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-12l-3.172-3.172a4 4 0 00-5.656 0L28 12M12 32l3.172-3.172a4 4 0 015.656 0L32 32" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
<p style="margin: 0;">Click to upload or drag and drop</p>
|
||||
<p class="hint">PNG, JPG, GIF, WebP up to 5MB</p>
|
||||
</div>
|
||||
<div id="file-list"></div>
|
||||
@error('reference_images.*')
|
||||
<p class="error-message">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Library Agreement -->
|
||||
<div class="form-section">
|
||||
<h2>Design Library</h2>
|
||||
|
||||
<div class="checkbox-group">
|
||||
<label class="checkbox-option">
|
||||
<input type="checkbox" name="library_discount" value="1" {{ old('library_discount') ? 'checked' : '' }}>
|
||||
<div class="checkbox-content">
|
||||
<p style="font-weight: 600; margin-bottom: 0.25rem;">Allow us to use your design in our library</p>
|
||||
<p>If you agree, we'll apply a <strong>20% discount to the design fee</strong>. This means we may offer similar designs to other customers in the future.</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit Buttons -->
|
||||
<div class="button-group">
|
||||
<button type="submit" class="btn">Submit Order</button>
|
||||
<a href="{{ route('my-orders') }}" class="btn btn-cancel">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Cost Summary Sidebar -->
|
||||
<div class="cost-summary">
|
||||
<div class="cost-summary-content">
|
||||
<h3>Cost Summary</h3>
|
||||
|
||||
<div class="cost-item disabled" id="material-cost-item">
|
||||
<span class="cost-label">Material Cost</span>
|
||||
<span class="cost-value">-</span>
|
||||
</div>
|
||||
|
||||
<div class="cost-item disabled" id="design-fee-item">
|
||||
<span class="cost-label">Design Fee</span>
|
||||
<span class="cost-value">-</span>
|
||||
</div>
|
||||
|
||||
<div class="cost-item disabled" id="discount-item" style="display: none;">
|
||||
<span class="cost-label">Library Discount</span>
|
||||
<span class="cost-value">-</span>
|
||||
</div>
|
||||
|
||||
<div class="cost-item total">
|
||||
<span>Deposit Required (20%)</span>
|
||||
<span class="cost-value" id="deposit-amount">R0.00</span>
|
||||
</div>
|
||||
|
||||
<div class="design-fee-note">
|
||||
<strong>Note:</strong> 20% non-refundable deposit covers design work. Pay the remaining 80% after proof approval.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="background: var(--accent-light); padding: 1.5rem; border-radius: 20px; margin-bottom: 1rem;">
|
||||
<p style="margin: 0 0 0.5rem 0; color: black;">Estimated Total:</p>
|
||||
<div style="font-family: 'Abril Fatface', cursive; font-size: 3rem; font-weight: 400; color: white;">R<span id="total-cost">0.00</span></div>
|
||||
<small style="color: #fff; display: block; margin-top: 0.5rem;">incl. VAT</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Total Cost Display -->
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('=== CUSTOM ORDER FORM DEBUG ===');
|
||||
|
||||
const form = document.getElementById('custom-order-form');
|
||||
console.log('Form element:', form);
|
||||
console.log('Form action:', form.action);
|
||||
console.log('Form method:', form.method);
|
||||
console.log('Form enctype:', form.enctype);
|
||||
console.log('Form ID:', form.id);
|
||||
console.log('Form classes:', form.className);
|
||||
|
||||
if (!form) {
|
||||
console.error('FORM NOT FOUND!');
|
||||
return;
|
||||
}
|
||||
|
||||
// ===== COST CALCULATION =====
|
||||
const DESIGN_FEE = 500; // Base design fee in Rands
|
||||
const DISCOUNT_PERCENTAGE = 0.20; // 20% discount for library usage
|
||||
|
||||
// Get form inputs
|
||||
const typeSelect = document.getElementById('type');
|
||||
const widthInput = document.getElementById('width');
|
||||
const heightInput = document.getElementById('height');
|
||||
const quantityInput = document.getElementById('quantity');
|
||||
const stockSelect = document.getElementById('print_stock_id');
|
||||
const libraryCheckbox = document.querySelector('input[name="library_discount"]');
|
||||
|
||||
// Get summary elements
|
||||
const materialCostItem = document.getElementById('material-cost-item');
|
||||
const designFeeItem = document.getElementById('design-fee-item');
|
||||
const discountItem = document.getElementById('discount-item');
|
||||
const depositAmount = document.getElementById('deposit-amount');
|
||||
|
||||
// Store print stocks data
|
||||
const printStocksData = {};
|
||||
@foreach($printStocks as $stock)
|
||||
printStocksData[{{ $stock->id }}] = {
|
||||
name: '{{ $stock->name }}',
|
||||
width: {{ $stock->width ?? 0.53 }},
|
||||
costPerMeter: {{ $stock->cost_per_meter ?? 0 }},
|
||||
costPerM2: {{ $stock->cost_per_m2 ?? 0 }}
|
||||
};
|
||||
@endforeach
|
||||
|
||||
function calculateCosts() {
|
||||
const type = typeSelect.value;
|
||||
const width = parseFloat(widthInput.value) || 0;
|
||||
const height = parseFloat(heightInput.value) || 0;
|
||||
const quantity = parseFloat(quantityInput.value) || 1;
|
||||
const stockId = stockSelect.value;
|
||||
const hasLibraryDiscount = libraryCheckbox?.checked || false;
|
||||
|
||||
if (!type || !stockId || width <= 0 || height <= 0) {
|
||||
// Show disabled state
|
||||
materialCostItem.classList.add('disabled');
|
||||
designFeeItem.classList.add('disabled');
|
||||
discountItem.style.display = 'none';
|
||||
depositAmount.textContent = 'R0.00';
|
||||
document.getElementById('total-cost').textContent = '0.00';
|
||||
document.getElementById('cost-breakdown').textContent = '';
|
||||
return;
|
||||
}
|
||||
|
||||
const stock = printStocksData[stockId];
|
||||
if (!stock) return;
|
||||
|
||||
// Calculate material cost based on type
|
||||
let materialCost = 0;
|
||||
let breakdown = '';
|
||||
|
||||
if (type === 'wallpaper') {
|
||||
// Wallpaper: Takes into account stock width
|
||||
// Calculate number of vertical strips needed: ceil(wall_height / stock_width)
|
||||
// Calculate total length: number_of_strips × wall_width
|
||||
// Cost = total_length × cost_per_meter × quantity
|
||||
const stockWidth = stock.width || 0.53; // Default to standard wallpaper width if not specified
|
||||
const stripsNeeded = Math.ceil(height / stockWidth);
|
||||
const totalLength = stripsNeeded * width;
|
||||
materialCost = totalLength * stock.costPerMeter * quantity;
|
||||
breakdown = `Stock: R${stock.costPerMeter.toFixed(2)}/m × ${totalLength.toFixed(2)}m`;
|
||||
} else if (type === 'mural') {
|
||||
// Mural: width × height in m²
|
||||
// Cost = cost_per_m2 × (width × height) × quantity
|
||||
const area = width * height;
|
||||
materialCost = area * stock.costPerM2 * quantity;
|
||||
breakdown = `Stock: R${stock.costPerM2.toFixed(2)}/m² × ${area.toFixed(2)}m²`;
|
||||
} else if (type === 'fabric') {
|
||||
// Fabric: width input = length in linear meters
|
||||
// Cost = cost_per_meter × length × quantity
|
||||
materialCost = width * stock.costPerMeter * quantity;
|
||||
breakdown = `Stock: R${stock.costPerMeter.toFixed(2)}/m × ${width.toFixed(2)}m`;
|
||||
}
|
||||
|
||||
// Calculate design fee
|
||||
let designFee = DESIGN_FEE;
|
||||
let discount = 0;
|
||||
|
||||
if (hasLibraryDiscount) {
|
||||
discount = designFee * DISCOUNT_PERCENTAGE;
|
||||
designFee -= discount;
|
||||
}
|
||||
|
||||
// Total cost
|
||||
const totalCost = materialCost + designFee;
|
||||
const depositRequired = totalCost * 0.20; // 20% deposit
|
||||
const remainingBalance = totalCost * 0.80; // 80% remaining
|
||||
|
||||
// Update UI
|
||||
materialCostItem.classList.remove('disabled');
|
||||
materialCostItem.innerHTML = `<span class="cost-label">Material Cost</span><span class="cost-value">R${materialCost.toFixed(2)}</span>`;
|
||||
|
||||
designFeeItem.classList.remove('disabled');
|
||||
designFeeItem.innerHTML = `<span class="cost-label">Design Fee</span><span class="cost-value">R${designFee.toFixed(2)}</span>`;
|
||||
|
||||
if (hasLibraryDiscount && discount > 0) {
|
||||
discountItem.style.display = 'flex';
|
||||
discountItem.classList.add('discount');
|
||||
discountItem.innerHTML = `<span class="cost-label">Library Discount (20%)</span><span class="cost-value">-R${discount.toFixed(2)}</span>`;
|
||||
} else {
|
||||
discountItem.style.display = 'none';
|
||||
}
|
||||
|
||||
depositAmount.textContent = `R${depositRequired.toFixed(2)}`;
|
||||
document.getElementById('total-cost').textContent = `${totalCost.toFixed(2)}`;
|
||||
document.getElementById('cost-breakdown').textContent = breakdown;
|
||||
}
|
||||
|
||||
// Add event listeners for cost calculation
|
||||
if (typeSelect) typeSelect.addEventListener('change', calculateCosts);
|
||||
if (widthInput) widthInput.addEventListener('input', calculateCosts);
|
||||
if (heightInput) heightInput.addEventListener('input', calculateCosts);
|
||||
if (quantityInput) quantityInput.addEventListener('input', calculateCosts);
|
||||
if (stockSelect) stockSelect.addEventListener('change', calculateCosts);
|
||||
if (libraryCheckbox) libraryCheckbox.addEventListener('change', calculateCosts);
|
||||
|
||||
// Update field labels based on type
|
||||
function updateFieldLabels() {
|
||||
const type = typeSelect.value;
|
||||
const widthLabel = document.querySelector('label[for="width"]');
|
||||
const heightLabel = document.querySelector('label[for="height"]');
|
||||
const heightGroup = heightInput?.parentElement;
|
||||
|
||||
if (type === 'wallpaper') {
|
||||
if (widthLabel) widthLabel.innerHTML = 'Wall Width (meters) *';
|
||||
if (heightLabel) heightLabel.innerHTML = 'Wall Height (meters) *<br><small style="font-weight: normal; color: var(--text-secondary); display: block; margin-top: 0.25rem;">The system will calculate strips needed based on stock width</small>';
|
||||
if (heightGroup) heightGroup.style.display = 'block';
|
||||
} else if (type === 'mural') {
|
||||
if (widthLabel) widthLabel.textContent = 'Width (meters) *';
|
||||
if (heightGroup) heightGroup.style.display = 'block';
|
||||
if (heightLabel) heightLabel.textContent = 'Height (meters) *';
|
||||
} else if (type === 'fabric') {
|
||||
if (widthLabel) widthLabel.textContent = 'Length (meters) *';
|
||||
if (heightGroup) heightGroup.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
if (typeSelect) {
|
||||
typeSelect.addEventListener('change', updateFieldLabels);
|
||||
}
|
||||
|
||||
// Initial label update
|
||||
updateFieldLabels();
|
||||
|
||||
// Initial calculation
|
||||
calculateCosts();
|
||||
|
||||
// Handle reference image uploads
|
||||
const referenceImagesInput = document.getElementById('reference-images');
|
||||
if (referenceImagesInput) {
|
||||
referenceImagesInput.addEventListener('change', function() {
|
||||
const fileList = document.getElementById('file-list');
|
||||
if (fileList) {
|
||||
fileList.innerHTML = '';
|
||||
|
||||
for (let file of this.files) {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'file-item';
|
||||
item.innerHTML = `<svg fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4z" clip-rule="evenodd"/></svg><span>${file.name}</span>`;
|
||||
fileList.appendChild(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Find the submit button and log when it's clicked
|
||||
const submitBtn = form.querySelector('button[type="submit"]');
|
||||
if (submitBtn) {
|
||||
console.log('Submit button found:', submitBtn);
|
||||
submitBtn.addEventListener('click', function(e) {
|
||||
console.log('===== SUBMIT BUTTON CLICKED =====');
|
||||
console.log('Event:', e);
|
||||
console.log('Form will submit to:', form.action);
|
||||
});
|
||||
}
|
||||
|
||||
// Handle form submission - FORCE IT TO SUBMIT
|
||||
form.addEventListener('submit', function(e) {
|
||||
console.log('===== FORM SUBMIT EVENT FIRED =====');
|
||||
console.log('Event type:', e.type);
|
||||
console.log('Event defaultPrevented:', e.defaultPrevented);
|
||||
console.log('Action:', form.action);
|
||||
console.log('Method:', form.method);
|
||||
console.log('About to submit to:', form.action);
|
||||
console.log('Checking if global script should skip this form...');
|
||||
console.log('Form action includes /custom-orders:', form.action.includes('/custom-orders'));
|
||||
// Don't prevent - let it submit naturally
|
||||
});
|
||||
|
||||
console.log('Event listeners attached successfully');
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
@@ -0,0 +1,150 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Deposit Payment Successful')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
.success-container {
|
||||
max-width: 600px;
|
||||
margin: var(--spacing-xl) auto;
|
||||
padding: var(--spacing-xl);
|
||||
background-color: var(--accent-light);
|
||||
border: 2px solid var(--accent-pink);
|
||||
border-radius: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
font-size: 4rem;
|
||||
color: var(--accent-pink);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.success-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: 2rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.success-message {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.order-details {
|
||||
background-color: white;
|
||||
padding: var(--spacing-lg);
|
||||
border-radius: 8px;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: var(--spacing-sm) 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.detail-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
color: var(--text-secondary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.next-steps {
|
||||
text-align: left;
|
||||
background-color: white;
|
||||
padding: var(--spacing-lg);
|
||||
border-radius: 8px;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.next-steps h3 {
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.next-steps ol {
|
||||
color: var(--text-secondary);
|
||||
padding-left: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.next-steps li {
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: var(--spacing-md);
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.action-buttons .btn {
|
||||
flex: 1;
|
||||
min-width: 150px;
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="success-container">
|
||||
<div class="success-icon">✓</div>
|
||||
<h1 class="success-title">Payment Successful!</h1>
|
||||
<p class="success-message">
|
||||
Your deposit payment has been received and processed successfully.
|
||||
</p>
|
||||
|
||||
<div class="order-details">
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">Order Number:</span>
|
||||
<span class="detail-value">{{ $customOrder->order_number }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">Order Type:</span>
|
||||
<span class="detail-value">{{ ucfirst($customOrder->type) }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">Deposit Amount:</span>
|
||||
<span class="detail-value">R{{ number_format($customOrder->deposit_amount, 2) }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">Remaining Balance:</span>
|
||||
<span class="detail-value">R{{ number_format($customOrder->balance_amount, 2) }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">Payment Status:</span>
|
||||
<span class="detail-value"><span class="status-badge paid">Paid</span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="next-steps">
|
||||
<h3>What Happens Next?</h3>
|
||||
<ol>
|
||||
<li>Your design requirements have been received</li>
|
||||
<li>Our design team will review your specifications</li>
|
||||
<li>You'll receive proof designs for your approval within 3-5 business days</li>
|
||||
<li>Once you approve the proofs, we'll prepare for printing</li>
|
||||
<li>The remaining balance (80%) will be due before printing begins</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<a href="{{ route('custom-orders.show', $customOrder) }}" class="btn">View Order Details</a>
|
||||
<a href="{{ route('my-orders') }}" class="btn btn--secondary">Back to Orders</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,355 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'My Custom Orders')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.6rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.page-header-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.page-header p {
|
||||
color: var(--text-secondary);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
background-color: var(--bg-secondary);
|
||||
border-radius: 8px;
|
||||
padding: var(--spacing-xl);
|
||||
text-align: center;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.empty-state-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.empty-state h2 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.orders-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
||||
gap: var(--spacing-lg);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.order-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.order-card:hover {
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.order-card-header {
|
||||
padding: var(--spacing-lg);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.order-number {
|
||||
font-family: var(--font-sans);
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.order-date {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.order-card-body {
|
||||
padding: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.order-detail {
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.order-detail:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.order-detail-label {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
font-size: 0.9rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.order-detail-value {
|
||||
color: var(--text-secondary);
|
||||
font-size: 1rem;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.order-details-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.order-card-footer {
|
||||
padding: var(--spacing-lg);
|
||||
border-top: 1px solid var(--border-color);
|
||||
display: flex;
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.order-card-footer a {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.progress-indicator {
|
||||
display: flex;
|
||||
gap: var(--spacing-sm);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.progress-step {
|
||||
flex: 1;
|
||||
height: 4px;
|
||||
background-color: var(--border-color);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-step.active {
|
||||
background-color: var(--accent-dark);
|
||||
}
|
||||
|
||||
.progress-step.completed {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
|
||||
.status-flow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.status-flow-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.status-flow-arrow {
|
||||
color: var(--border-color);
|
||||
margin: 0 0.25rem;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: var(--spacing-md);
|
||||
border-radius: 8px;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #e8f5e9;
|
||||
border-color: #c8e6c9;
|
||||
color: #2e7d32;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.orders-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.order-details-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.order-card-footer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.order-card-footer a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.status-flow {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container" style="margin-top:20px;">
|
||||
@if (session('success'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="page-header">
|
||||
<div class="page-header-content">
|
||||
<h1>My Custom Orders</h1>
|
||||
<p>Track and manage your custom printing orders</p>
|
||||
</div>
|
||||
<a href="{{ route('custom-orders.create') }}" class="btn">Create New Order</a>
|
||||
</div>
|
||||
|
||||
@if ($customOrders->isEmpty())
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-icon">📋</div>
|
||||
<h2>No Custom Orders Yet</h2>
|
||||
<p>You haven't created any custom orders yet. Start by designing your unique print today!</p>
|
||||
<a href="{{ route('custom-orders.create') }}" class="btn">Create Your First Order</a>
|
||||
</div>
|
||||
@else
|
||||
<div class="orders-grid">
|
||||
@foreach ($customOrders as $order)
|
||||
<div class="order-card">
|
||||
<div class="order-card-header">
|
||||
<div>
|
||||
<div class="order-number">Order #{{ $order->order_number }}</div>
|
||||
<div class="order-date">{{ $order->created_at->format('d M Y') }}</div>
|
||||
</div>
|
||||
<span class="status-badge {{ $order->status }}">
|
||||
{{ str_replace('_', ' ', ucfirst($order->status)) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="order-card-body">
|
||||
<!-- Progress Indicator -->
|
||||
<div class="progress-indicator">
|
||||
@php
|
||||
$statuses = ['submitted', 'approved', 'in_production', 'proof_ready', 'completed'];
|
||||
$currentIndex = array_search($order->status, $statuses);
|
||||
@endphp
|
||||
@foreach ($statuses as $index => $status)
|
||||
<div class="progress-step {{ $index <= $currentIndex ? 'completed' : ($index === $currentIndex + 1 ? 'active' : '') }}"></div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<!-- Order Details Grid -->
|
||||
<div class="order-details-grid">
|
||||
<div class="order-detail">
|
||||
<div class="order-detail-label">Type</div>
|
||||
<div class="order-detail-value">{{ ucfirst($order->type) }}</div>
|
||||
</div>
|
||||
|
||||
<div class="order-detail">
|
||||
<div class="order-detail-label">Status</div>
|
||||
<div class="order-detail-value">
|
||||
{{ str_replace('_', ' ', ucfirst($order->status)) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($order->specifications)
|
||||
<div class="order-detail">
|
||||
<div class="order-detail-label">Quantity</div>
|
||||
<div class="order-detail-value">{{ $order->specifications->quantity }}</div>
|
||||
</div>
|
||||
|
||||
<div class="order-detail">
|
||||
<div class="order-detail-label">Stock</div>
|
||||
<div class="order-detail-value">
|
||||
{{ $order->specifications->printStock ? $order->specifications->printStock->name : 'N/A' }}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Payment Status -->
|
||||
@if ($order->total_cost)
|
||||
<div class="order-detail">
|
||||
<div class="order-detail-label">Total Cost</div>
|
||||
<div class="order-detail-value" style="font-weight: 600; color: var(--accent-dark); font-size: 1.1rem;">
|
||||
R{{ number_format($order->total_cost, 2) }}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Status Flow -->
|
||||
<div class="status-flow">
|
||||
<div class="status-flow-item">
|
||||
<span>{{ $order->deposit_status === 'paid' ? '✓' : '○' }}</span>
|
||||
<span>Deposit</span>
|
||||
</div>
|
||||
<div class="status-flow-arrow">→</div>
|
||||
<div class="status-flow-item">
|
||||
<span>{{ $order->status === 'approved' ? '✓' : '○' }}</span>
|
||||
<span>Approved</span>
|
||||
</div>
|
||||
<div class="status-flow-arrow">→</div>
|
||||
<div class="status-flow-item">
|
||||
<span>{{ in_array($order->status, ['in_production', 'proof_ready', 'completed']) ? '✓' : '○' }}</span>
|
||||
<span>Production</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-card-footer">
|
||||
<a href="{{ route('custom-orders.show', $order->uuid) }}">View Details</a>
|
||||
@if ($order->deposit_status === 'unpaid')
|
||||
<a href="{{ route('custom-orders.show', $order->uuid) }}" class="secondary">Pay Deposit</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,431 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Order #' . $customOrder->order_number . ' - Custom Order Details')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
/* Page-specific typography overrides */
|
||||
h1 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 2.5rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: 'Abril Fatface', cursive;
|
||||
font-size: 1.6rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.page-intro {
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.page-intro p {
|
||||
color: var(--text-secondary);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Timeline-specific styles */
|
||||
.card {
|
||||
padding: var(--spacing-lg);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.timeline-container {
|
||||
background: white;
|
||||
padding: var(--spacing-lg);
|
||||
border-radius: 20px;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.timeline-container:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.timeline-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: 1.3rem;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
position: relative;
|
||||
overflow-x: auto;
|
||||
padding: var(--spacing-md) 0;
|
||||
}
|
||||
|
||||
.timeline::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background-color: var(--border-color);
|
||||
z-index: 1;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
flex: 1;
|
||||
min-width: 140px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.timeline-circle {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: white;
|
||||
border: 3px solid var(--border-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
font-weight: 900;
|
||||
font-size: 1.2rem;
|
||||
color: var(--text-primary);
|
||||
flex-shrink: 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.timeline-item.completed .timeline-circle {
|
||||
background-color: var(--accent-pink);
|
||||
border-color: var(--accent-pink);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.timeline-item.active .timeline-circle {
|
||||
background-color: var(--accent-light);
|
||||
border-color: var(--accent-dark);
|
||||
box-shadow: 0 0 0 4px var(--accent-light);
|
||||
}
|
||||
|
||||
.timeline-label {
|
||||
text-align: center;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
line-height: 1.3;
|
||||
max-width: 120px;
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
.timeline-item.completed .timeline-label {
|
||||
color: var(--accent-pink);
|
||||
}
|
||||
|
||||
.timeline-item.active .timeline-label {
|
||||
color: var(--accent-dark);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.content-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.image-gallery {
|
||||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="page-intro">
|
||||
<h1>Custom Order Details</h1>
|
||||
<p>Order #{{ $customOrder->order_number }}</p>
|
||||
</div>
|
||||
|
||||
@if (session('success'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (session('info'))
|
||||
<div class="alert alert-info">
|
||||
{{ session('info') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Timeline -->
|
||||
<div class="timeline-container">
|
||||
<h2 class="timeline-title">Order Progress</h2>
|
||||
<div class="timeline">
|
||||
@php
|
||||
$timelineSteps = [
|
||||
['status' => 'submitted', 'label' => 'Order\nSubmitted', 'completed' => $customOrder->status !== null],
|
||||
['status' => 'deposit_paid', 'label' => 'Deposit\nPaid', 'completed' => $customOrder->deposit_status === 'paid'],
|
||||
['status' => 'proof_sent', 'label' => 'Proofs\nSent', 'completed' => $customOrder->proofs()->exists()],
|
||||
['status' => 'proof_approved', 'label' => 'Proofs\nApproved', 'completed' => $customOrder->proofs()->where('status', 'approved')->exists()],
|
||||
['status' => 'processing', 'label' => 'Processing', 'completed' => $customOrder->status === 'processing'],
|
||||
['status' => 'shipped', 'label' => 'Order\nShipped', 'completed' => $customOrder->status === 'completed'],
|
||||
];
|
||||
|
||||
// Determine current step
|
||||
$currentStep = 0;
|
||||
if ($customOrder->status === 'completed') $currentStep = 5;
|
||||
elseif ($customOrder->status === 'processing') $currentStep = 4;
|
||||
elseif ($customOrder->proofs()->where('status', 'approved')->exists()) $currentStep = 3;
|
||||
elseif ($customOrder->proofs()->exists()) $currentStep = 2;
|
||||
elseif ($customOrder->deposit_status === 'paid') $currentStep = 1;
|
||||
@endphp
|
||||
|
||||
@foreach ($timelineSteps as $index => $step)
|
||||
<div class="timeline-item @if ($index < $currentStep) completed @elseif ($index === $currentStep) active @endif">
|
||||
<div class="timeline-circle">
|
||||
@if ($index < $currentStep)
|
||||
✓
|
||||
@else
|
||||
{{ $index + 1 }}
|
||||
@endif
|
||||
</div>
|
||||
<div class="timeline-label">{{ $step['label'] }}</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-grid">
|
||||
<!-- Main Content -->
|
||||
<div>
|
||||
<!-- Order Status -->
|
||||
<div class="card">
|
||||
<h2>Order Status</h2>
|
||||
<div class="card-section">
|
||||
<span class="status-badge {{ $customOrder->status }}">
|
||||
{{ str_replace('_', ' ', ucfirst($customOrder->status)) }}
|
||||
</span>
|
||||
<p style="margin-top: var(--spacing-sm); color: var(--text-secondary); font-size: 0.9rem;">
|
||||
Submitted on {{ $customOrder->created_at->format('d M Y \a\t H:i') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Design Requirements -->
|
||||
<div class="card">
|
||||
<h2>Design Requirements</h2>
|
||||
|
||||
<div class="card-section">
|
||||
<h3>Order Type</h3>
|
||||
<p style="color: var(--text-secondary); text-transform: capitalize;">{{ $customOrder->type }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card-section">
|
||||
<h3>Dimensions</h3>
|
||||
@if ($customOrder->specifications)
|
||||
<dl style="color: var(--text-secondary);">
|
||||
@if ($customOrder->specifications->length)
|
||||
<div class="spec-group">
|
||||
<dt>Length:</dt>
|
||||
<dd>{{ $customOrder->specifications->length }}m</dd>
|
||||
</div>
|
||||
@endif
|
||||
@if ($customOrder->specifications->width)
|
||||
<div class="spec-group">
|
||||
<dt>Width:</dt>
|
||||
<dd>{{ $customOrder->specifications->width }}m</dd>
|
||||
</div>
|
||||
@endif
|
||||
@if ($customOrder->specifications->height)
|
||||
<div class="spec-group">
|
||||
<dt>Height:</dt>
|
||||
<dd>{{ $customOrder->specifications->height }}m</dd>
|
||||
</div>
|
||||
@endif
|
||||
<div class="spec-group">
|
||||
<dt>Quantity:</dt>
|
||||
<dd>{{ $customOrder->specifications->quantity }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="card-section">
|
||||
<h3>Print Material</h3>
|
||||
@if ($customOrder->specifications->printStock)
|
||||
<p style="color: var(--text-secondary);">{{ $customOrder->specifications->printStock->name }}</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="card-section">
|
||||
<h3>Design Brief</h3>
|
||||
<p style="color: var(--text-secondary);">{{ $customOrder->customer_brief }}</p>
|
||||
</div>
|
||||
|
||||
@if ($customOrder->specifications->special_instructions)
|
||||
<div class="card-section">
|
||||
<h3>Special Instructions</h3>
|
||||
<p style="color: var(--text-secondary);">{{ $customOrder->specifications->special_instructions }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Reference Images -->
|
||||
@if ($customOrder->files->count() > 0)
|
||||
<div class="card">
|
||||
<h2>Reference Images</h2>
|
||||
<div class="image-gallery">
|
||||
@foreach ($customOrder->files as $file)
|
||||
<a href="{{ Storage::url($file->file_path) }}" target="_blank" title="{{ $file->original_filename }}">
|
||||
<img src="{{ Storage::url($file->file_path) }}" alt="{{ $file->original_filename }}">
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Design Proofs -->
|
||||
@if ($customOrder->proofs->count() > 0)
|
||||
<div class="card">
|
||||
<h2>Design Proofs</h2>
|
||||
@foreach ($customOrder->proofs as $proof)
|
||||
<div class="proof-item {{ $proof->status === 'approved' ? 'approved' : '' }}">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--spacing-sm);">
|
||||
<h3>Proof {{ $loop->iteration }}</h3>
|
||||
<span class="status-badge {{ $proof->status }}">
|
||||
{{ ucfirst($proof->status) }}
|
||||
</span>
|
||||
</div>
|
||||
@if ($proof->file_path)
|
||||
<a href="{{ Storage::url($proof->file_path) }}" target="_blank" style="color: var(--accent-dark); text-decoration: underline; font-size: 0.9rem;">
|
||||
View Proof File
|
||||
</a>
|
||||
@endif
|
||||
@if ($proof->feedback)
|
||||
<div style="margin-top: var(--spacing-sm); padding: var(--spacing-sm); background: white; border-radius: 4px; border-left: 3px solid var(--accent-dark);">
|
||||
<strong style="color: var(--text-primary); font-size: 0.9rem;">Feedback:</strong>
|
||||
<p style="color: var(--text-secondary); font-size: 0.85rem; margin: var(--spacing-xs) 0 0 0;">{{ $proof->feedback }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div>
|
||||
<!-- Cost & Payment Summary -->
|
||||
<div class="card">
|
||||
<h2>Order Summary</h2>
|
||||
|
||||
<!-- Cost Summary -->
|
||||
<div class="payment-section">
|
||||
<div class="payment-row">
|
||||
<span>Design Fee:</span>
|
||||
<span>R{{ number_format($customOrder->design_fee, 2) }}</span>
|
||||
</div>
|
||||
@if ($customOrder->material_cost > 0)
|
||||
<div class="payment-row">
|
||||
<span>Material Cost:</span>
|
||||
<span>R{{ number_format($customOrder->material_cost, 2) }}</span>
|
||||
</div>
|
||||
@endif
|
||||
<div class="payment-row total">
|
||||
<span>Total:</span>
|
||||
<span>R{{ number_format($customOrder->total_cost, 2) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Payment Status -->
|
||||
<h3 style="margin-top: var(--spacing-lg); margin-bottom: var(--spacing-md);">Payment Status</h3>
|
||||
|
||||
<div style="padding: var(--spacing-sm); background-color: var(--accent-light); border-radius: 20px; margin-bottom: var(--spacing-md);">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--spacing-xs);">
|
||||
<strong>Deposit (20%)</strong>
|
||||
<span class="status-badge {{ $customOrder->deposit_status }}">{{ ucfirst($customOrder->deposit_status) }}</span>
|
||||
</div>
|
||||
<p style="color: var(--text-secondary); margin: 0; font-size: 0.9rem;">R{{ number_format($customOrder->deposit_amount, 2) }}</p>
|
||||
</div>
|
||||
|
||||
<div style="padding: var(--spacing-sm); background-color: var(--accent-light); border-radius: 20px; margin-bottom: var(--spacing-lg);">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--spacing-xs);">
|
||||
<strong>Balance (80%)</strong>
|
||||
<span class="status-badge {{ $customOrder->balance_status }}">{{ ucfirst($customOrder->balance_status) }}</span>
|
||||
</div>
|
||||
<p style="color: var(--text-secondary); margin: 0; font-size: 0.9rem;">R{{ number_format($customOrder->balance_amount, 2) }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Payment Buttons -->
|
||||
@if ($customOrder->deposit_status !== 'paid')
|
||||
<form method="POST" action="{{ route('yoco-custom-deposit') }}">
|
||||
@csrf
|
||||
<input type="hidden" name="custom_order_id" value="{{ $customOrder->id }}">
|
||||
<button type="submit" class="btn">Pay Deposit (R{{ number_format($customOrder->deposit_amount, 2) }})</button>
|
||||
</form>
|
||||
@elseif ($customOrder->deposit_status === 'paid' && $customOrder->proofs->where('status', 'approved')->count() > 0 && $customOrder->balance_status !== 'paid')
|
||||
<button class="btn" onclick="alert('Balance payment coming soon')">Pay Balance (R{{ number_format($customOrder->balance_amount, 2) }})</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Terms -->
|
||||
<div class="terms-box">
|
||||
<h3 style="color: var(--text-primary); margin-top: 0;">Payment Terms</h3>
|
||||
<ul>
|
||||
<li>The 20% deposit is non-refundable</li>
|
||||
<li>Balance of 80% must be paid before printing begins</li>
|
||||
@if ($customOrder->library_discount_applied)
|
||||
<li>Design may be added to our library</li>
|
||||
@else
|
||||
<li>Bespoke, exclusive design</li>
|
||||
@endif
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const paymentForm = document.querySelector('form[action*="payment"]');
|
||||
if (paymentForm) {
|
||||
console.log('Payment form found:', paymentForm);
|
||||
console.log('Form action:', paymentForm.action);
|
||||
|
||||
paymentForm.addEventListener('submit', function(e) {
|
||||
console.log('Payment form submitted!');
|
||||
console.log('Form data:', new FormData(this));
|
||||
});
|
||||
} else {
|
||||
console.log('Payment form NOT found');
|
||||
console.log('All forms on page:', document.querySelectorAll('form'));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
@@ -68,29 +68,6 @@
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 0.4rem 1rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status-processing {
|
||||
background-color: #cfe2ff;
|
||||
color: #084298;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background-color: #d1e7dd;
|
||||
color: #0f5132;
|
||||
}
|
||||
|
||||
.order-total {
|
||||
text-align: right;
|
||||
}
|
||||
@@ -196,7 +173,7 @@
|
||||
</div>
|
||||
|
||||
<div class="order-status">
|
||||
<span class="status-badge status-{{ $order->status }}">
|
||||
<span class="status-badge {{ $order->status }}">
|
||||
{{ ucfirst($order->status) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -428,7 +428,7 @@
|
||||
<!-- Print Stock Selection -->
|
||||
<div class="quantity-selector" style="flex-direction: column; align-items: flex-start; gap: 0.5rem; margin-bottom: 2rem;">
|
||||
<label for="print_stock_id" style="font-weight: 600;">Select Print Stock:</label>
|
||||
<select id="print_stock_id" name="print_stock_id" required style="width: 100%; padding: 0.75rem; border: 1px solid #ddd; border-radius: 4px; font-size: 1rem;">
|
||||
<select id="print_stock_id" name="print_stock_id" required style=" font-family: var(--font-sans); width: 100%; padding: 0.75rem; border: 1px solid #ddd; border-radius: 4px; font-size: 1rem;">
|
||||
@foreach($product->printStocks as $stock)
|
||||
<option value="{{ $stock->id }}"
|
||||
data-cost="{{ $product->type === 'wallpaper' ? $stock->cost_per_meter : $stock->cost_per_m2 }}"
|
||||
@@ -450,7 +450,7 @@
|
||||
|
||||
<div class="quantity-selector" style="flex-direction: column; align-items: flex-start; gap: 0.5rem;">
|
||||
<label for="length">Length Required (meters):</label>
|
||||
<input type="number" id="length" name="length" min="1" step="0.5" value="3" required style="width: 150px;">
|
||||
<input type="number" id="length" name="length" min="1" step="0.5" value="3" required style="font-family: var(--font-sans); width: 150px;">
|
||||
<small style="color: #666;">Recommended: Add 0.5m for pattern matching and trimming</small>
|
||||
</div>
|
||||
@elseif($product->type === 'mural')
|
||||
@@ -540,12 +540,12 @@
|
||||
|
||||
<div class="calc-input-group">
|
||||
<label for="calc-wall-width">Wall Width (meters):</label>
|
||||
<input type="number" id="calc-wall-width" min="0.1" step="0.1" value="4" oninput="calculateWallpaper()">
|
||||
<input style="font-family: var(--font-sans);" type="number" id="calc-wall-width" min="0.1" step="0.1" value="4" oninput="calculateWallpaper()">
|
||||
</div>
|
||||
|
||||
<div class="calc-input-group">
|
||||
<label for="calc-wall-height">Wall Height (meters):</label>
|
||||
<input type="number" id="calc-wall-height" min="0.1" step="0.1" value="2.7" oninput="calculateWallpaper()">
|
||||
<input style="font-family: var(--font-sans);" type="number" id="calc-wall-height" min="0.1" step="0.1" value="2.7" oninput="calculateWallpaper()">
|
||||
</div>
|
||||
|
||||
<div class="calc-input-group">
|
||||
|
||||
Reference in New Issue
Block a user