generated from boboko/starter
order emails theming, sold out product card, contact page hcaptcha
This commit is contained in:
@@ -19,7 +19,7 @@ final class ProductCard
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $product one item from ProductService's localized array shape
|
||||
* @return array{name: ?string, price: ?string, image: ?string, href: string, variantId: ?int, hasCustomFields: bool}
|
||||
* @return array{name: ?string, price: ?string, image: ?string, href: string, variantId: ?int, hasCustomFields: bool, soldOut: bool}
|
||||
*/
|
||||
public static function fromIndexed(array $product): array
|
||||
{
|
||||
@@ -38,6 +38,10 @@ public static function fromIndexed(array $product): array
|
||||
// can't be quick-added from a card — the card links to the
|
||||
// product page instead, even when every field is optional.
|
||||
'hasCustomFields' => ! empty($product['custom_fields']),
|
||||
// Index-time stock (see boboko-core's ProductIndexer `in_stock`),
|
||||
// so only as fresh as the last reindex. A document missing the
|
||||
// field is treated as in stock rather than hiding its cart button.
|
||||
'soldOut' => ! ($product['in_stock'] ?? true),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Rules\HCaptcha;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ContactRequest extends FormRequest
|
||||
@@ -17,6 +18,14 @@ public function rules(): array
|
||||
'name' => ['required', 'string', 'max:100'],
|
||||
'email' => ['required', 'email', 'max:255'],
|
||||
'message' => ['required', 'string', 'max:5000'],
|
||||
'h-captcha-response' => ['bail', 'required', new HCaptcha],
|
||||
];
|
||||
}
|
||||
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'h-captcha-response.required' => __('storefront.auth.captcha_failed'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@
|
||||
'email' => env('CONTACT_EMAIL'),
|
||||
],
|
||||
|
||||
// Bot check on guest forms (login), verified by App\Rules\HCaptcha. For
|
||||
// Bot check on guest forms (login, contact), verified by App\Rules\HCaptcha. For
|
||||
// local dev use hCaptcha's test keys, the real ones reject localhost:
|
||||
// sitekey 10000000-ffff-ffff-ffff-000000000001,
|
||||
// secret 0x0000000000000000000000000000000000000000.
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
:href="$product['href'] ?? '#'"
|
||||
:variant-id="$product['variantId'] ?? null"
|
||||
:has-custom-fields="$product['hasCustomFields'] ?? false"
|
||||
:sold-out="$product['soldOut'] ?? false"
|
||||
/>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
'href' => '#',
|
||||
'variantId' => null,
|
||||
'hasCustomFields' => false,
|
||||
// Shows the "sold" star and drops the quick add-to-cart/personalize button.
|
||||
'soldOut' => false,
|
||||
// Heart toggle at the top right of the image; needs productId.
|
||||
'productId' => null,
|
||||
'wishlist' => false,
|
||||
@@ -36,7 +38,9 @@ class="w-full h-auto block"
|
||||
<x-wishlist-button :product-id="$productId" class="absolute top-4 right-4 z-10" />
|
||||
@endif
|
||||
|
||||
@if ($hasCustomFields)
|
||||
@if ($soldOut)
|
||||
<x-ui.sold-badge class="absolute top-2 right-2 {{ $wishlist && $productId ? 'mt-12' : '' }}" />
|
||||
@elseif ($hasCustomFields)
|
||||
{{-- Custom fields have to be filled in on the product page. --}}
|
||||
<x-ui.button
|
||||
:href="$href"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{{-- Black "sold" star for out-of-stock products. Position it from the caller
|
||||
(e.g. class="absolute top-2 right-2"). --}}
|
||||
<div {{ $attributes->class('z-10 flex h-20 w-22 items-center justify-center text-black') }}>
|
||||
<svg viewBox="0 0 87 80" class="absolute inset-0 size-full" fill="currentColor" aria-hidden="true">
|
||||
<path d="M56.942,0l2.607,18.642,19.143-3.363L69.468,31.842,87,40,69.468,48.158l9.224,16.563L59.549,61.358,56.942,80,43.5,66.4,30.058,80,27.451,61.358,8.308,64.721l9.224-16.563L0,40l17.532-8.158L8.308,15.279l19.143,3.363L30.058,0,43.5,13.6Z"/>
|
||||
</svg>
|
||||
<span class="relative text-base italic font-black text-white uppercase">{{ __('storefront.product.sold') }}</span>
|
||||
</div>
|
||||
@@ -3,6 +3,11 @@
|
||||
@section('title', __('storefront.nav.contact'))
|
||||
@section('description', 'Επικοινώνησε μαζί μας για οποιαδήποτε απορία ή ιδέα έχεις και θα σου απαντήσουμε το συντομότερο δυνατό.')
|
||||
|
||||
{{-- Only on pages with a captcha, not in the global layout. --}}
|
||||
@push('scripts')
|
||||
<script src="https://js.hcaptcha.com/1/api.js?hl={{ app()->getLocale() }}" async defer></script>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
|
||||
<section class="grid grid-cols-1 lg:grid-cols-2 lg:divide-x lg:divide-black lg:min-h-[calc(100vh-102px)]">
|
||||
@@ -30,25 +35,35 @@
|
||||
@csrf
|
||||
|
||||
<div class="grid grid-cols-1 gap-8 sm:grid-cols-2">
|
||||
<x-ui.field label="Το όνομά σου" for="contact-name" :error="$errors->first('name')">
|
||||
<x-ui.field label="Το όνομά σου *" for="contact-name" :error="$errors->first('name')">
|
||||
<x-ui.input id="contact-name" name="name" autocomplete="name" maxlength="100" :value="old('name')" :required="true"
|
||||
:aria-invalid="$errors->has('name') ? 'true' : null"
|
||||
:aria-describedby="$errors->has('name') ? 'contact-name-error' : null" />
|
||||
</x-ui.field>
|
||||
|
||||
<x-ui.field label="Το email σου" for="contact-email" :error="$errors->first('email')">
|
||||
<x-ui.field label="Το email σου *" for="contact-email" :error="$errors->first('email')">
|
||||
<x-ui.input id="contact-email" name="email" type="email" autocomplete="email" maxlength="255" :value="old('email')" :required="true"
|
||||
:aria-invalid="$errors->has('email') ? 'true' : null"
|
||||
:aria-describedby="$errors->has('email') ? 'contact-email-error' : null" />
|
||||
</x-ui.field>
|
||||
</div>
|
||||
|
||||
<x-ui.field label="Το μήνυμά σου" for="contact-message" :error="$errors->first('message')">
|
||||
<x-ui.field label="Το μήνυμά σου *" for="contact-message" :error="$errors->first('message')">
|
||||
<x-ui.textarea id="contact-message" name="message" rows="5" maxlength="5000" :required="true"
|
||||
:aria-invalid="$errors->has('message') ? 'true' : null"
|
||||
:aria-describedby="$errors->has('message') ? 'contact-message-error' : null">{{ old('message') }}</x-ui.textarea>
|
||||
</x-ui.field>
|
||||
|
||||
{{-- hCaptcha checkbox, verified by App\Rules\HCaptcha (see auth/login). --}}
|
||||
<x-ui.field for="contact-captcha" :error="$errors->first('h-captcha-response')">
|
||||
<div
|
||||
id="contact-captcha"
|
||||
class="h-captcha min-h-[78px]"
|
||||
data-sitekey="{{ config('services.hcaptcha.sitekey') }}"
|
||||
@if ($errors->has('h-captcha-response')) aria-describedby="contact-captcha-error" @endif
|
||||
></div>
|
||||
</x-ui.field>
|
||||
|
||||
@if (session('contact_error'))
|
||||
<p role="alert" class="text-sm text-red-600">{{ session('contact_error') }}</p>
|
||||
@endif
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
@media only screen and (max-width: 480px) {
|
||||
.email-container { width: 100% !important; max-width: 100% !important; }
|
||||
.email-header { padding: 24px 20px 12px !important; }
|
||||
.email-gutter { padding: 0 !important; }
|
||||
.email-card { padding: 28px 20px !important; }
|
||||
.email-footer { padding: 0 20px 32px !important; }
|
||||
}
|
||||
@@ -69,7 +70,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:0 24px;">
|
||||
<td class="email-gutter" style="padding:0 24px;">
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" bgcolor="#ffffff" style="background-color:#ffffff;border-radius:0;">
|
||||
<tr>
|
||||
<td class="email-card" style="padding:40px 32px;font-family:'Manrope',Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#000000;text-align:left;">
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{{--
|
||||
@include('emails.partials.address', ['address' => $order->shippingAddress])
|
||||
|
||||
An order address, read-only, same fields as the account order page.
|
||||
--}}
|
||||
<p style="margin:0;font-size:15px;line-height:1.6;">
|
||||
{{ trim($address->first_name.' '.$address->last_name) }}<br>
|
||||
@if ($address->company_name){{ $address->company_name }}<br>@endif
|
||||
@if ($address->tax_identifier)ΑΦΜ: {{ $address->tax_identifier }}<br>@endif
|
||||
{{ $address->line_one }}<br>
|
||||
@if ($address->line_two){{ $address->line_two }}<br>@endif
|
||||
{{ trim($address->postcode.' '.$address->city) }}<br>
|
||||
@if ($address->state){{ Lang::has("core::states.{$address->state}") ? __("core::states.{$address->state}") : $address->state }}<br>@endif
|
||||
@if ($address->contact_phone){{ $address->contact_phone }}@endif
|
||||
</p>
|
||||
@@ -0,0 +1,13 @@
|
||||
{{--
|
||||
@include('emails.partials.button', ['url' => ..., 'label' => ...])
|
||||
|
||||
Bulletproof button: the padding sits on the link (whole area clickable)
|
||||
with mso-padding-alt on the cell so Outlook keeps the same size.
|
||||
--}}
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" style="margin:0;">
|
||||
<tr>
|
||||
<td bgcolor="#18c28a" style="background-color:#18c28a;border:1px solid #000000;border-radius:0;mso-padding-alt:14px 28px;">
|
||||
<a href="{{ $url }}" target="_blank" style="display:inline-block;padding:14px 28px;font-family:'Manrope',Arial,Helvetica,sans-serif;font-size:16px;line-height:1.2;font-weight:700;color:#000000;text-decoration:none;">{{ $label }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,2 @@
|
||||
{{-- @include('emails.partials.section-heading', ['text' => ...]) --}}
|
||||
<h2 style="margin:0 0 12px;padding:0 0 8px;border-bottom:1px solid #000000;font-family:'Manrope',Arial,Helvetica,sans-serif;font-size:18px;line-height:1.3;font-weight:800;color:#000000;">{{ $text }}</h2>
|
||||
@@ -43,7 +43,7 @@ class="absolute left-4 lg:left-8 top-1/2 z-10 -translate-y-1/2 hover:-translate-
|
||||
class="{{ $loop->first ? '' : 'hidden' }} group h-full flex flex-col justify-center pb-8 relative"
|
||||
>
|
||||
<div class="relative flex items-center justify-center">
|
||||
<a href="{{ $product['href'] }}" class="block border border-black bg-white flex items-center justify-center overflow-hidden max-w-xs xl:max-w-sm">
|
||||
<a href="{{ $product['href'] }}" class="relative block border border-black bg-white flex items-center justify-center overflow-hidden max-w-xs xl:max-w-sm">
|
||||
@if($product['image'])
|
||||
<img
|
||||
src="{{ $product['image'] }}"
|
||||
@@ -58,9 +58,16 @@ class="w-full h-full object-cover"
|
||||
@else
|
||||
<span class="text-neutral-500 text-sm">{{ __('storefront.product.no_image') }}</span>
|
||||
@endif
|
||||
|
||||
{{-- Inside the link so it sits on the image's corner, not the full-width slide's. --}}
|
||||
@if ($product['soldOut'] ?? false)
|
||||
<x-ui.sold-badge class="absolute top-2 right-2" />
|
||||
@endif
|
||||
</a>
|
||||
|
||||
@if ($product['hasCustomFields'] ?? false)
|
||||
@if ($product['soldOut'] ?? false)
|
||||
{{-- Sold: no quick add-to-cart/personalize, same as x-ui.product-card. --}}
|
||||
@elseif ($product['hasCustomFields'] ?? false)
|
||||
<x-ui.button
|
||||
:href="$product['href']"
|
||||
size="md"
|
||||
@@ -173,6 +180,7 @@ class="max-w-xs"
|
||||
:href="$product['href']"
|
||||
:variant-id="$product['variantId'] ?? null"
|
||||
:has-custom-fields="$product['hasCustomFields'] ?? false"
|
||||
:sold-out="$product['soldOut'] ?? false"
|
||||
/>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
<p>Hi,</p>
|
||||
{{-- Core passes only the order reference here (and the amount for payment emails). Greek on purpose: sent from the queue in the app default locale. --}}
|
||||
@extends('emails.layout')
|
||||
|
||||
<p>Payment of <strong>{{ $amount }}</strong> for your order <strong>{{ $reference }}</strong> has been captured.</p>
|
||||
@section('title', "Λάβαμε την πληρωμή σου")
|
||||
|
||||
@section('preheader', "Λάβαμε την πληρωμή {$amount} για την παραγγελία #{$reference}.")
|
||||
|
||||
@section('content')
|
||||
<h1 style="margin:0 0 16px;font-family:'Manrope',Arial,Helvetica,sans-serif;font-size:22px;line-height:1.3;font-weight:700;color:#000000;">
|
||||
Λάβαμε την πληρωμή σου
|
||||
</h1>
|
||||
|
||||
<p style="margin:0 0 32px;">Λάβαμε την πληρωμή σου <strong>{{ $amount }}</strong> για την παραγγελία <strong>#{{ $reference }}</strong>.</p>
|
||||
|
||||
@include('emails.partials.button', [
|
||||
'url' => route('account.orders', ['locale' => 'el']),
|
||||
'label' => 'Οι παραγγελίες μου',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('footer')
|
||||
<p style="margin:0;">
|
||||
Έχεις ερώτηση για την παραγγελία σου;
|
||||
<a href="{{ route('contact', ['locale' => 'el']) }}" style="color:#7a7a7a;text-decoration:underline;">Επικοινώνησε μαζί μας</a>.
|
||||
</p>
|
||||
@endsection
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
<p>Hi,</p>
|
||||
{{-- Core passes only the order reference here (and the amount for payment emails). Greek on purpose: sent from the queue in the app default locale. --}}
|
||||
@extends('emails.layout')
|
||||
|
||||
<p>Your order <strong>{{ $reference }}</strong> is complete. Thanks for shopping with us!</p>
|
||||
@section('title', "Η παραγγελία σου ολοκληρώθηκε")
|
||||
|
||||
@section('preheader', "Η παραγγελία σου #{$reference} ολοκληρώθηκε.")
|
||||
|
||||
@section('content')
|
||||
<h1 style="margin:0 0 16px;font-family:'Manrope',Arial,Helvetica,sans-serif;font-size:22px;line-height:1.3;font-weight:700;color:#000000;">
|
||||
Η παραγγελία σου ολοκληρώθηκε
|
||||
</h1>
|
||||
|
||||
<p style="margin:0 0 32px;">Η παραγγελία σου <strong>#{{ $reference }}</strong> ολοκληρώθηκε. Ευχαριστούμε που ψώνισες από εμάς!</p>
|
||||
|
||||
@include('emails.partials.button', [
|
||||
'url' => route('account.orders', ['locale' => 'el']),
|
||||
'label' => 'Οι παραγγελίες μου',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('footer')
|
||||
<p style="margin:0;">
|
||||
Έχεις ερώτηση για την παραγγελία σου;
|
||||
<a href="{{ route('contact', ['locale' => 'el']) }}" style="color:#7a7a7a;text-decoration:underline;">Επικοινώνησε μαζί μας</a>.
|
||||
</p>
|
||||
@endsection
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
<p>Hi,</p>
|
||||
{{-- Core passes only the order reference here (and the amount for payment emails). Greek on purpose: sent from the queue in the app default locale. --}}
|
||||
@extends('emails.layout')
|
||||
|
||||
<p>Good news — your order <strong>{{ $reference }}</strong> has been delivered.</p>
|
||||
@section('title', "Η παραγγελία σου παραδόθηκε")
|
||||
|
||||
@section('preheader', "Η παραγγελία σου #{$reference} παραδόθηκε.")
|
||||
|
||||
@section('content')
|
||||
<h1 style="margin:0 0 16px;font-family:'Manrope',Arial,Helvetica,sans-serif;font-size:22px;line-height:1.3;font-weight:700;color:#000000;">
|
||||
Η παραγγελία σου παραδόθηκε
|
||||
</h1>
|
||||
|
||||
<p style="margin:0 0 32px;">Η παραγγελία σου <strong>#{{ $reference }}</strong> παραδόθηκε. Ελπίζουμε να σου αρέσει!</p>
|
||||
|
||||
@include('emails.partials.button', [
|
||||
'url' => route('account.orders', ['locale' => 'el']),
|
||||
'label' => 'Οι παραγγελίες μου',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('footer')
|
||||
<p style="margin:0;">
|
||||
Έχεις ερώτηση για την παραγγελία σου;
|
||||
<a href="{{ route('contact', ['locale' => 'el']) }}" style="color:#7a7a7a;text-decoration:underline;">Επικοινώνησε μαζί μας</a>.
|
||||
</p>
|
||||
@endsection
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
<p>Hi,</p>
|
||||
{{-- Core passes only the order reference here (and the amount for payment emails). Greek on purpose: sent from the queue in the app default locale. --}}
|
||||
@extends('emails.layout')
|
||||
|
||||
<p>Your order <strong>{{ $reference }}</strong> is on its way.</p>
|
||||
@section('title', "Η παραγγελία σου στάλθηκε")
|
||||
|
||||
@section('preheader', "Η παραγγελία σου #{$reference} είναι καθ’ οδόν.")
|
||||
|
||||
@section('content')
|
||||
<h1 style="margin:0 0 16px;font-family:'Manrope',Arial,Helvetica,sans-serif;font-size:22px;line-height:1.3;font-weight:700;color:#000000;">
|
||||
Η παραγγελία σου στάλθηκε
|
||||
</h1>
|
||||
|
||||
<p style="margin:0 0 32px;">Η παραγγελία σου <strong>#{{ $reference }}</strong> είναι καθ’ οδόν. Θα τη λάβεις σύντομα.</p>
|
||||
|
||||
@include('emails.partials.button', [
|
||||
'url' => route('account.orders', ['locale' => 'el']),
|
||||
'label' => 'Οι παραγγελίες μου',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('footer')
|
||||
<p style="margin:0;">
|
||||
Έχεις ερώτηση για την παραγγελία σου;
|
||||
<a href="{{ route('contact', ['locale' => 'el']) }}" style="color:#7a7a7a;text-decoration:underline;">Επικοινώνησε μαζί μας</a>.
|
||||
</p>
|
||||
@endsection
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
<p>Hi,</p>
|
||||
{{-- Core passes only the order reference here (and the amount for payment emails). Greek on purpose: sent from the queue in the app default locale. --}}
|
||||
@extends('emails.layout')
|
||||
|
||||
<p>Your order <strong>{{ $reference }}</strong> is ready for pickup in store.</p>
|
||||
@section('title', "Η παραγγελία σου είναι έτοιμη για παραλαβή")
|
||||
|
||||
@section('preheader', "Η παραγγελία σου #{$reference} σε περιμένει στο κατάστημα.")
|
||||
|
||||
@section('content')
|
||||
<h1 style="margin:0 0 16px;font-family:'Manrope',Arial,Helvetica,sans-serif;font-size:22px;line-height:1.3;font-weight:700;color:#000000;">
|
||||
Η παραγγελία σου είναι έτοιμη για παραλαβή
|
||||
</h1>
|
||||
|
||||
<p style="margin:0 0 32px;">Η παραγγελία σου <strong>#{{ $reference }}</strong> είναι έτοιμη και σε περιμένει στο κατάστημα.</p>
|
||||
|
||||
@include('emails.partials.button', [
|
||||
'url' => route('account.orders', ['locale' => 'el']),
|
||||
'label' => 'Οι παραγγελίες μου',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('footer')
|
||||
<p style="margin:0;">
|
||||
Έχεις ερώτηση για την παραγγελία σου;
|
||||
<a href="{{ route('contact', ['locale' => 'el']) }}" style="color:#7a7a7a;text-decoration:underline;">Επικοινώνησε μαζί μας</a>.
|
||||
</p>
|
||||
@endsection
|
||||
|
||||
+172
-16
@@ -1,19 +1,175 @@
|
||||
<p>Hi,</p>
|
||||
{{--
|
||||
Order confirmation (boboko-core's OrderPlacedNotification).
|
||||
|
||||
<p>Thanks for your order! Your order <strong>{{ $reference }}</strong> is confirmed.</p>
|
||||
Core only passes $reference, $total and $lines, so the order itself is
|
||||
reached through a line (every OrderLine belongs to it). Interim until core
|
||||
passes the Order to this view.
|
||||
|
||||
<ul>
|
||||
@foreach ($lines as $line)
|
||||
<li>
|
||||
{{ $line->quantity }} × {{ $line->description }} — {{ $line->total?->formatted }}
|
||||
{{-- Text answers only — photo answers are deliberately left out of emails. --}}
|
||||
@foreach ($line->meta['custom_fields'] ?? [] as $field)
|
||||
@if ($field['type'] !== 'file')
|
||||
<br>{{ $field['label'] }}: {!! nl2br(e($field['value'])) !!}
|
||||
@endif
|
||||
@endforeach
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
Sent from the queue with no locale of its own, so it always renders in the
|
||||
app default (Greek). Copy is Greek on purpose, like the other core emails.
|
||||
--}}
|
||||
@extends('emails.layout')
|
||||
|
||||
<p>Total: <strong>{{ $total }}</strong></p>
|
||||
@php
|
||||
$order = $lines->first()->order;
|
||||
$productLines = $lines->where('type', '!=', 'shipping');
|
||||
$shippingLine = $lines->firstWhere('type', 'shipping');
|
||||
|
||||
// By type, like the account order page: the method may since have been
|
||||
// disabled, but the order still shows what was used.
|
||||
$paymentMethodName = \Modules\Core\Payment\Models\PaymentMethod::where('type', $order->meta['payment_method'] ?? null)
|
||||
->first()
|
||||
?->translate('name');
|
||||
|
||||
// Lunar doesn't copy the coupon onto the order; the cart row keeps it.
|
||||
$couponCode = $order->cart?->coupon_code;
|
||||
|
||||
$email = $order->billingAddress?->contact_email ?? $order->shippingAddress?->contact_email;
|
||||
$comments = $order->shippingAddress?->delivery_instructions;
|
||||
|
||||
$muted = 'color:#5c5c5c;font-size:14px;';
|
||||
$font = "font-family:'Manrope',Arial,Helvetica,sans-serif;";
|
||||
@endphp
|
||||
|
||||
@section('title', "Η παραγγελία σου #{$reference} επιβεβαιώθηκε")
|
||||
|
||||
@section('preheader', "Ευχαριστούμε! Λάβαμε την παραγγελία σου #{$reference}, σύνολο {$total}.")
|
||||
|
||||
@section('content')
|
||||
<h1 style="margin:0 0 16px;{{ $font }}font-size:22px;line-height:1.3;font-weight:700;color:#000000;">
|
||||
Ευχαριστούμε για την παραγγελία σου!
|
||||
</h1>
|
||||
|
||||
<p style="margin:0 0 24px;">
|
||||
Λάβαμε την παραγγελία σου <strong>#{{ $reference }}</strong>
|
||||
στις {{ $order->placed_at?->format('d/m/Y') }}.
|
||||
Θα σε ενημερώσουμε με email μόλις σταλεί.
|
||||
</p>
|
||||
|
||||
<div style="margin:0 0 40px;">
|
||||
@include('emails.partials.button', [
|
||||
'url' => route('account.orders.show', ['locale' => 'el', 'orderId' => $order->id]),
|
||||
'label' => 'Δες την παραγγελία σου',
|
||||
])
|
||||
</div>
|
||||
|
||||
{{-- Items --}}
|
||||
@include('emails.partials.section-heading', ['text' => 'Προϊόντα'])
|
||||
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:0 0 8px;">
|
||||
@foreach ($productLines as $line)
|
||||
<tr>
|
||||
<td width="64" valign="top" style="width:64px;padding:12px 12px 12px 0;{{ $loop->last ? '' : 'border-bottom:1px solid #e5e5e5;' }}">
|
||||
@if ($thumb = $line->purchasable?->getThumbnailImage())
|
||||
<img src="{{ $thumb }}" width="64" height="64" alt="{{ $line->description }}" style="display:block;width:64px;height:64px;object-fit:cover;background-color:#e5e5e5;border:0;{{ $font }}font-size:11px;color:#5c5c5c;">
|
||||
@else
|
||||
<div style="width:64px;height:64px;background-color:#e5e5e5;"></div>
|
||||
@endif
|
||||
</td>
|
||||
<td valign="top" style="padding:12px 12px 12px 0;{{ $font }}font-size:15px;line-height:1.4;color:#000000;{{ $loop->last ? '' : 'border-bottom:1px solid #e5e5e5;' }}">
|
||||
<strong>{{ $line->description }}</strong>
|
||||
|
||||
@if ($line->option)
|
||||
<br><span style="{{ $muted }}">{{ $line->option }}</span>
|
||||
@endif
|
||||
|
||||
{{-- Text answers only: photo answers are deliberately left out of emails. --}}
|
||||
@foreach ($line->meta['custom_fields'] ?? [] as $field)
|
||||
@if ($field['type'] !== 'file' && filled($field['value'] ?? null))
|
||||
<br><span style="{{ $muted }}">{{ $field['label'] }}: {!! nl2br(e($field['value'])) !!}</span>
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
<br><span style="{{ $muted }}">
|
||||
Ποσότητα: {{ $line->quantity }}@if ($line->quantity > 1) × {{ $line->unit_price->formatted() }}@endif
|
||||
</span>
|
||||
</td>
|
||||
<td valign="top" align="right" style="padding:12px 0;white-space:nowrap;{{ $font }}font-size:15px;line-height:1.4;font-weight:700;color:#000000;{{ $loop->last ? '' : 'border-bottom:1px solid #e5e5e5;' }}">
|
||||
{{ $line->sub_total?->formatted() }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
|
||||
{{-- Totals --}}
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:0 0 40px;border-top:1px solid #000000;">
|
||||
<tr>
|
||||
<td style="padding:12px 0 4px;{{ $font }}font-size:15px;color:#000000;">Υποσύνολο</td>
|
||||
<td align="right" style="padding:12px 0 4px;white-space:nowrap;{{ $font }}font-size:15px;color:#000000;">{{ $order->sub_total?->formatted() }}</td>
|
||||
</tr>
|
||||
|
||||
@if ($order->discount_total?->value > 0)
|
||||
<tr>
|
||||
<td style="padding:4px 0;{{ $font }}font-size:15px;color:#000000;">
|
||||
Έκπτωση@if ($couponCode) <span style="{{ $muted }}">({{ $couponCode }})</span>@endif
|
||||
</td>
|
||||
<td align="right" style="padding:4px 0;white-space:nowrap;{{ $font }}font-size:15px;color:#000000;">−{{ $order->discount_total->formatted() }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
<tr>
|
||||
<td style="padding:4px 0;{{ $font }}font-size:15px;color:#000000;">
|
||||
Μεταφορικά@if ($shippingLine) <span style="{{ $muted }}">({{ $shippingLine->description }})</span>@endif
|
||||
</td>
|
||||
<td align="right" style="padding:4px 0;white-space:nowrap;{{ $font }}font-size:15px;color:#000000;">
|
||||
{{ $order->shipping_total?->value > 0 ? $order->shipping_total->formatted() : 'Δωρεάν' }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td style="padding:12px 0 0;border-top:1px solid #000000;{{ $font }}font-size:20px;line-height:1.3;font-weight:800;color:#000000;">Σύνολο</td>
|
||||
<td align="right" style="padding:12px 0 0;border-top:1px solid #000000;white-space:nowrap;{{ $font }}font-size:20px;line-height:1.3;font-weight:800;color:#000000;">{{ $total }}</td>
|
||||
</tr>
|
||||
|
||||
{{-- Prices include VAT (lunar.pricing.stored_inclusive_of_tax), so this is informational. --}}
|
||||
@if ($order->tax_total?->value > 0)
|
||||
<tr>
|
||||
<td colspan="2" align="right" style="padding:4px 0 0;{{ $font }}{{ $muted }}">Περιλαμβάνεται Φ.Π.Α. {{ $order->tax_total->formatted() }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
</table>
|
||||
|
||||
{{-- Payment + shipping --}}
|
||||
@include('emails.partials.section-heading', ['text' => 'Πληρωμή και αποστολή'])
|
||||
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:0 0 40px;">
|
||||
@foreach (array_filter([
|
||||
'Τρόπος πληρωμής' => $paymentMethodName,
|
||||
'Τρόπος αποστολής' => $shippingLine?->description,
|
||||
'Παραστατικό' => ($order->meta['wants_invoice'] ?? false) ? 'Τιμολόγιο' : 'Απόδειξη',
|
||||
'Email' => $email,
|
||||
]) as $label => $value)
|
||||
<tr>
|
||||
<td valign="top" style="padding:4px 12px 4px 0;{{ $font }}{{ $muted }}line-height:1.5;">{{ $label }}</td>
|
||||
<td valign="top" align="right" style="padding:4px 0;{{ $font }}font-size:15px;line-height:1.5;color:#000000;word-break:break-word;">{{ $value }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
|
||||
{{-- Addresses: stacked, never side by side, so they read well on a phone. --}}
|
||||
@if ($order->shippingAddress)
|
||||
@include('emails.partials.section-heading', ['text' => 'Διεύθυνση αποστολής'])
|
||||
<div style="margin:0 0 {{ $comments ? '16px' : '40px' }};">
|
||||
@include('emails.partials.address', ['address' => $order->shippingAddress])
|
||||
</div>
|
||||
|
||||
@if ($comments)
|
||||
<p style="margin:0 0 40px;font-size:15px;line-height:1.6;">
|
||||
<span style="{{ $muted }}">Σχόλια</span><br>
|
||||
{!! nl2br(e($comments)) !!}
|
||||
</p>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if ($order->billingAddress)
|
||||
@include('emails.partials.section-heading', ['text' => 'Στοιχεία χρέωσης'])
|
||||
@include('emails.partials.address', ['address' => $order->billingAddress])
|
||||
@endif
|
||||
@endsection
|
||||
|
||||
@section('footer')
|
||||
<p style="margin:0;">
|
||||
Έχεις ερώτηση για την παραγγελία σου;
|
||||
<a href="{{ route('contact', ['locale' => 'el']) }}" style="color:#7a7a7a;text-decoration:underline;">Επικοινώνησε μαζί μας</a>.
|
||||
</p>
|
||||
@endsection
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
<p>Hi,</p>
|
||||
{{-- Core passes only the order reference here (and the amount for payment emails). Greek on purpose: sent from the queue in the app default locale. --}}
|
||||
@extends('emails.layout')
|
||||
|
||||
<p>A refund of <strong>{{ $amount }}</strong> has been issued for your order <strong>{{ $reference }}</strong>.</p>
|
||||
@section('title', "Έγινε επιστροφή χρημάτων")
|
||||
|
||||
@section('preheader', "Επιστρέψαμε {$amount} για την παραγγελία #{$reference}.")
|
||||
|
||||
@section('content')
|
||||
<h1 style="margin:0 0 16px;font-family:'Manrope',Arial,Helvetica,sans-serif;font-size:22px;line-height:1.3;font-weight:700;color:#000000;">
|
||||
Έγινε επιστροφή χρημάτων
|
||||
</h1>
|
||||
|
||||
<p style="margin:0 0 32px;">Σου επιστρέψαμε <strong>{{ $amount }}</strong> για την παραγγελία <strong>#{{ $reference }}</strong>.</p>
|
||||
|
||||
@include('emails.partials.button', [
|
||||
'url' => route('account.orders', ['locale' => 'el']),
|
||||
'label' => 'Οι παραγγελίες μου',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('footer')
|
||||
<p style="margin:0;">
|
||||
Έχεις ερώτηση για την παραγγελία σου;
|
||||
<a href="{{ route('contact', ['locale' => 'el']) }}" style="color:#7a7a7a;text-decoration:underline;">Επικοινώνησε μαζί μας</a>.
|
||||
</p>
|
||||
@endsection
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
<p>Hi,</p>
|
||||
{{-- Core passes only the order reference here (and the amount for payment emails). Greek on purpose: sent from the queue in the app default locale. --}}
|
||||
@extends('emails.layout')
|
||||
|
||||
<p>Your order <strong>{{ $reference }}</strong> is now: <strong>{{ $statusLabel }}</strong></p>
|
||||
@php
|
||||
// Core passes Lunar's English label; map it back to the status key so the
|
||||
// shared <x-order-status> can show the translated one. Interim, until core
|
||||
// passes the order (or its status) to this view.
|
||||
$status = collect(config('lunar.orders.statuses'))
|
||||
->search(fn (array $config) => $config['label'] === $statusLabel) ?: $statusLabel;
|
||||
@endphp
|
||||
|
||||
@section('title', "Ενημέρωση παραγγελίας")
|
||||
|
||||
@section('preheader', "Η παραγγελία σου #{$reference} ενημερώθηκε.")
|
||||
|
||||
@section('content')
|
||||
<h1 style="margin:0 0 16px;font-family:'Manrope',Arial,Helvetica,sans-serif;font-size:22px;line-height:1.3;font-weight:700;color:#000000;">
|
||||
Η παραγγελία σου ενημερώθηκε
|
||||
</h1>
|
||||
|
||||
<p style="margin:0 0 32px;">Η κατάσταση της παραγγελίας σου <strong>#{{ $reference }}</strong> είναι τώρα: <strong><x-order-status :status="$status" /></strong></p>
|
||||
|
||||
@include('emails.partials.button', [
|
||||
'url' => route('account.orders', ['locale' => 'el']),
|
||||
'label' => 'Οι παραγγελίες μου',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('footer')
|
||||
<p style="margin:0;">
|
||||
Έχεις ερώτηση για την παραγγελία σου;
|
||||
<a href="{{ route('contact', ['locale' => 'el']) }}" style="color:#7a7a7a;text-decoration:underline;">Επικοινώνησε μαζί μας</a>.
|
||||
</p>
|
||||
@endsection
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
:href="$product['href']"
|
||||
:variant-id="$product['variantId']"
|
||||
:has-custom-fields="$product['hasCustomFields']"
|
||||
:sold-out="$product['soldOut']"
|
||||
:product-id="$product['id']"
|
||||
:wishlist="true"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user