Compare commits
12 Commits
1.0.0-rc.2
...
1.0.0-rc.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae7f8ed2c9 | ||
|
|
a3a86f4b2f | ||
|
|
9c081574c8 | ||
|
|
11edccad02 | ||
|
|
7c796802be | ||
|
|
5cc43bc889 | ||
|
|
f094411f10 | ||
|
|
ccc477f291 | ||
|
|
7217d945a3 | ||
|
|
9185269874 | ||
|
|
e42e3b4c0d | ||
|
|
a7ae946797 |
@@ -55,6 +55,7 @@ RUN chmod +x artisan
|
||||
|
||||
RUN ./artisan vendor:publish --tag=public --force ## creates public/vendor/jsvalidation
|
||||
RUN ./artisan vendor:publish --tag=boilerplate-public --force --ansi ## creates public/vendor/boilerplate
|
||||
RUN ./artisan vendor:publish --tag=datatables-buttons --force --ansi ## creates public/vendor/datatables/buttons
|
||||
|
||||
## XXXvlab: 2025-09-25 these migration files are breaking first
|
||||
## install, but we had to resolve to not install from scratch and use
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers\Shop\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Repositories\Core\User\ShopCart;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
@@ -31,6 +32,7 @@ class LoginController extends Controller
|
||||
]);
|
||||
|
||||
if ($this->guard()->attempt($credentials, $request->get('remember'))) {
|
||||
ShopCart::migrateGuestCartToUser();
|
||||
$request->session()->regenerate();
|
||||
if (back()->getTargetUrl() === route('Shop.Orders.store')) {
|
||||
$route = 'Shop.Orders.order';
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Shop\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Shop\RegisterCustomer;
|
||||
use App\Repositories\Core\User\ShopCart;
|
||||
use App\Repositories\Shop\CustomerSaleChannels;
|
||||
use App\Repositories\Shop\CustomerAddresses;
|
||||
use App\Repositories\Shop\Customers;
|
||||
@@ -33,6 +34,7 @@ class RegisterController extends Controller
|
||||
$user = $this->create($request->all());
|
||||
|
||||
$this->guard()->login($user);
|
||||
ShopCart::migrateGuestCartToUser();
|
||||
|
||||
return $request->wantsJson()
|
||||
? new JsonResponse([], 201)
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Http\Controllers\Shop;
|
||||
use App\Repositories\Shop\CustomerAddresses;
|
||||
use App\Repositories\Shop\Customers;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class CustomerController extends Controller
|
||||
{
|
||||
@@ -56,10 +57,89 @@ class CustomerController extends Controller
|
||||
return redirect()->route('Shop.Customers.edit');
|
||||
}
|
||||
|
||||
public function storeAddress(Request $request)
|
||||
{
|
||||
if (Customers::isNotConnected()) {
|
||||
return response()->json(['message' => __('Authentification requise.')], 403);
|
||||
}
|
||||
|
||||
$prefix = $request->input('prefix');
|
||||
$types = ['deliveries' => 1, 'invoices' => 2];
|
||||
|
||||
if (! array_key_exists($prefix, $types)) {
|
||||
return response()->json(['message' => __('Type d\'adresse inconnu.')], 422);
|
||||
}
|
||||
|
||||
$addressData = $request->input($prefix, []);
|
||||
|
||||
$validator = Validator::make($addressData, [
|
||||
'name' => ['nullable', 'string', 'max:150'],
|
||||
'address' => ['required', 'string', 'max:255'],
|
||||
'address2' => ['nullable', 'string', 'max:255'],
|
||||
'zipcode' => ['required', 'string', 'max:30'],
|
||||
'city' => ['required', 'string', 'max:255'],
|
||||
], [
|
||||
'address.required' => __('Merci de renseigner l\'adresse.'),
|
||||
'zipcode.required' => __('Merci de renseigner le code postal.'),
|
||||
'city.required' => __('Merci de renseigner la ville.'),
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => __('Merci de vérifier les informations saisies.'),
|
||||
'errors' => $validator->errors(),
|
||||
], 422);
|
||||
}
|
||||
|
||||
$data = $validator->validated();
|
||||
$customerId = Customers::getId();
|
||||
$data['customer_id'] = $customerId;
|
||||
$data['type'] = $types[$prefix];
|
||||
|
||||
if (empty($data['name'])) {
|
||||
$data['name'] = Customers::getName($customerId);
|
||||
}
|
||||
|
||||
$address = CustomerAddresses::store($data);
|
||||
CustomerAddresses::setDefault($customerId, $address->id, $types[$prefix]);
|
||||
|
||||
$html = view('Shop.Customers.partials.address_item', [
|
||||
'address' => $address->toArray(),
|
||||
'prefix' => $prefix,
|
||||
'with_name' => true,
|
||||
'selected' => $address->id,
|
||||
])->render();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'html' => $html,
|
||||
'message' => __('Adresse enregistrée.'),
|
||||
'id' => $address->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function delete_address($id)
|
||||
{
|
||||
$ret = CustomerAddresses::destroy($id);
|
||||
$address = CustomerAddresses::get($id);
|
||||
|
||||
return redirect()->route('Shop.Customers.edit');
|
||||
if (! $address || (int) $address->customer_id !== (int) Customers::getId()) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$remaining = CustomerAddresses::getModel()
|
||||
->byCustomer($address->customer_id)
|
||||
->byType($address->type)
|
||||
->count();
|
||||
|
||||
if ($remaining <= 1) {
|
||||
return redirect()->route('Shop.Customers.edit')
|
||||
->with('growl', [__('Vous devez conserver au moins une adresse par type.'), 'warning']);
|
||||
}
|
||||
|
||||
CustomerAddresses::destroy($id);
|
||||
CustomerAddresses::ensureDefault($address->customer_id, $address->type);
|
||||
|
||||
return redirect()->route('Shop.Customers.edit')
|
||||
->with('growl', [__('Adresse supprimée.'), 'success']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
namespace App\Models\Shop;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class CustomerAddress extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
protected $guarded = ['id'];
|
||||
|
||||
protected $table = 'shop_customer_addresses';
|
||||
|
||||
@@ -39,7 +39,7 @@ class Invoice extends Model
|
||||
|
||||
public function address(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(CustomerAddress::class, 'invoice_address_id');
|
||||
return $this->belongsTo(CustomerAddress::class, 'invoice_address_id')->withTrashed();
|
||||
}
|
||||
|
||||
public function scopeByCustomer($query, $customerId)
|
||||
|
||||
@@ -29,7 +29,7 @@ class Order extends Model
|
||||
|
||||
public function delivery_address(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(CustomerAddress::class, 'delivery_address_id');
|
||||
return $this->belongsTo(CustomerAddress::class, 'delivery_address_id')->withTrashed();
|
||||
}
|
||||
|
||||
public function delivery(): BelongsTo
|
||||
|
||||
@@ -94,11 +94,106 @@ class ShopCart
|
||||
return self::get()->getContent();
|
||||
}
|
||||
|
||||
public static function get()
|
||||
public static function migrateGuestCartToUser($userId = null)
|
||||
{
|
||||
$userId = Auth::guard('customer')->id();
|
||||
$sessionKey = 'cart_'.sha1(static::class . ($userId ?? 'guest'));
|
||||
$userId = self::resolveUserId($userId);
|
||||
|
||||
return Cart::session($sessionKey);
|
||||
if ($userId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$guestSessionKey = self::sessionKey();
|
||||
$guestItems = Cart::session($guestSessionKey)->getContent();
|
||||
|
||||
if ($guestItems->count() === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$userSessionKey = self::sessionKey($userId);
|
||||
|
||||
foreach ($guestItems as $item) {
|
||||
$existing = Cart::session($userSessionKey)->get($item->id);
|
||||
|
||||
if ($existing) {
|
||||
Cart::session($userSessionKey)->update($item->id, [
|
||||
'quantity' => [
|
||||
'relative' => false,
|
||||
'value' => $existing->quantity + $item->quantity,
|
||||
],
|
||||
]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$itemData = [
|
||||
'id' => $item->id,
|
||||
'name' => $item->name,
|
||||
'price' => $item->price,
|
||||
'quantity' => $item->quantity,
|
||||
'attributes' => self::extractAttributes($item),
|
||||
];
|
||||
|
||||
if (isset($item->associatedModel)) {
|
||||
$itemData['associatedModel'] = $item->associatedModel;
|
||||
}
|
||||
|
||||
$conditions = self::extractConditions($item);
|
||||
if (! empty($conditions)) {
|
||||
$itemData['conditions'] = $conditions;
|
||||
}
|
||||
|
||||
Cart::session($userSessionKey)->add($itemData);
|
||||
}
|
||||
|
||||
Cart::session($guestSessionKey)->clear();
|
||||
Cart::session($userSessionKey);
|
||||
}
|
||||
|
||||
protected static function extractAttributes($item)
|
||||
{
|
||||
if (! isset($item->attributes)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (is_object($item->attributes) && method_exists($item->attributes, 'toArray')) {
|
||||
return $item->attributes->toArray();
|
||||
}
|
||||
|
||||
return (array) $item->attributes;
|
||||
}
|
||||
|
||||
protected static function extractConditions($item)
|
||||
{
|
||||
if (! isset($item->conditions)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (is_object($item->conditions) && method_exists($item->conditions, 'toArray')) {
|
||||
return $item->conditions->toArray();
|
||||
}
|
||||
|
||||
return (array) $item->conditions;
|
||||
}
|
||||
|
||||
protected static function resolveUserId($userId = null)
|
||||
{
|
||||
return $userId ?? Auth::guard('customer')->id();
|
||||
}
|
||||
|
||||
protected static function sessionKey($userId = null)
|
||||
{
|
||||
$key = $userId ?? 'guest';
|
||||
|
||||
return 'cart_'.sha1(static::class.$key);
|
||||
}
|
||||
|
||||
protected static function session($userId = null)
|
||||
{
|
||||
return Cart::session(self::sessionKey($userId));
|
||||
}
|
||||
|
||||
public static function get($userId = null)
|
||||
{
|
||||
return self::session(self::resolveUserId($userId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,17 +12,35 @@ class CustomerAddresses
|
||||
public static function storeByCustomer($customer, $data)
|
||||
{
|
||||
$deliveries = $data['deliveries'] ?? false;
|
||||
if ($deliveries && $deliveries['zipcode'] && $deliveries['city']) {
|
||||
$deliveries['customer_id'] = $customer->id;
|
||||
$deliveries['type'] = 1;
|
||||
self::store($deliveries);
|
||||
if ($deliveries) {
|
||||
if (! empty($deliveries['address_id'])) {
|
||||
self::setDefault($customer->id, (int) $deliveries['address_id'], 1);
|
||||
}
|
||||
|
||||
if (! empty($deliveries['zipcode']) && ! empty($deliveries['city'])) {
|
||||
$payload = $deliveries;
|
||||
unset($payload['address_id']);
|
||||
$payload['customer_id'] = $customer->id;
|
||||
$payload['type'] = 1;
|
||||
$newAddress = self::store($payload);
|
||||
self::setDefault($customer->id, $newAddress->id, 1);
|
||||
}
|
||||
}
|
||||
|
||||
$invoices = $data['invoices'] ?? false;
|
||||
if ($invoices && $invoices['zipcode'] && $invoices['city']) {
|
||||
$invoices['customer_id'] = $customer->id;
|
||||
$invoices['type'] = 2;
|
||||
self::store($invoices);
|
||||
if ($invoices) {
|
||||
if (! empty($invoices['address_id'])) {
|
||||
self::setDefault($customer->id, (int) $invoices['address_id'], 2);
|
||||
}
|
||||
|
||||
if (! empty($invoices['zipcode']) && ! empty($invoices['city'])) {
|
||||
$payload = $invoices;
|
||||
unset($payload['address_id']);
|
||||
$payload['customer_id'] = $customer->id;
|
||||
$payload['type'] = 2;
|
||||
$newAddress = self::store($payload);
|
||||
self::setDefault($customer->id, $newAddress->id, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,14 +88,24 @@ class CustomerAddresses
|
||||
|
||||
public static function getInvoiceAddress($customerId)
|
||||
{
|
||||
$addresses = CustomerAddress::byCustomer($customerId)->byInvoicing()->get();
|
||||
return count($addresses) ? $addresses->first() : self::getByCustomer($customerId);
|
||||
$address = CustomerAddress::byCustomer($customerId)
|
||||
->byInvoicing()
|
||||
->orderByDesc('priority')
|
||||
->orderBy('id')
|
||||
->first();
|
||||
|
||||
return $address ?? self::getByCustomer($customerId);
|
||||
}
|
||||
|
||||
public static function getDeliveryAddress($customerId)
|
||||
{
|
||||
$addresses = CustomerAddress::byCustomer($customerId)->byDelivery()->get();
|
||||
return count($addresses) ? $addresses->first() : self::getByCustomer($customerId);
|
||||
$address = CustomerAddress::byCustomer($customerId)
|
||||
->byDelivery()
|
||||
->orderByDesc('priority')
|
||||
->orderBy('id')
|
||||
->first();
|
||||
|
||||
return $address ?? self::getByCustomer($customerId);
|
||||
}
|
||||
|
||||
public static function getByCustomer($customerId = false)
|
||||
@@ -92,6 +120,40 @@ class CustomerAddresses
|
||||
return ((int) $type === 1) ? '<i class="fa fa-fw fa-truck"></i>' : '<i class="fa fa-fw fa-file-invoice"></i>';
|
||||
}
|
||||
|
||||
public static function setDefault($customerId, $addressId, $type)
|
||||
{
|
||||
if (! $addressId) {
|
||||
return;
|
||||
}
|
||||
|
||||
$address = self::get($addressId);
|
||||
|
||||
if (! $address || (int) $address->customer_id !== (int) $customerId || (int) $address->type !== (int) $type) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::getModel()->byCustomer($customerId)->byType($type)->update(['priority' => null]);
|
||||
|
||||
$address->priority = 1;
|
||||
$address->save();
|
||||
}
|
||||
|
||||
public static function ensureDefault($customerId, $type)
|
||||
{
|
||||
$hasDefault = self::getModel()->byCustomer($customerId)->byType($type)->where('priority', 1)->exists();
|
||||
|
||||
if ($hasDefault) {
|
||||
return;
|
||||
}
|
||||
|
||||
$address = self::getModel()->byCustomer($customerId)->byType($type)->orderBy('id')->first();
|
||||
|
||||
if ($address) {
|
||||
$address->priority = 1;
|
||||
$address->save();
|
||||
}
|
||||
}
|
||||
|
||||
public static function toggleActive($id, $active)
|
||||
{
|
||||
return self::update(['active' => $active], $id);
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Datatables\Shop\CustomerInvoicesDataTable;
|
||||
use App\Datatables\Shop\CustomerOrdersDataTable;
|
||||
use App\Models\Shop\Customer;
|
||||
use App\Traits\Model\Basic;
|
||||
use App\Repositories\Shop\CustomerAddresses;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
@@ -95,6 +96,16 @@ class Customers
|
||||
$data = $customer->toArray();
|
||||
$data['sale_channels'] = $customer->sale_channels->pluck('id')->toArray();
|
||||
$data['deliveries'] = Deliveries::getBySaleChannels($data['sale_channels'])->toArray();
|
||||
$data['delivery_address_id'] = optional(CustomerAddresses::getDeliveryAddress($id))->id;
|
||||
$data['invoice_address_id'] = optional(CustomerAddresses::getInvoiceAddress($id))->id;
|
||||
|
||||
if (! $data['delivery_address_id'] && ! empty($data['delivery_addresses'])) {
|
||||
$data['delivery_address_id'] = $data['delivery_addresses'][0]['id'] ?? null;
|
||||
}
|
||||
|
||||
if (! $data['invoice_address_id'] && ! empty($data['invoice_addresses'])) {
|
||||
$data['invoice_address_id'] = $data['invoice_addresses'][0]['id'] ?? null;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -102,8 +113,8 @@ class Customers
|
||||
public static function storeFull($data)
|
||||
{
|
||||
$data2 = $data;
|
||||
if ($data['sale_channels'] ?? false) {
|
||||
$saleChannels = $data['sale_channels'] ?? false;
|
||||
$saleChannels = array_key_exists('sale_channels', $data) ? $data['sale_channels'] : null;
|
||||
if ($saleChannels !== null) {
|
||||
unset($data['sale_channels']);
|
||||
}
|
||||
if ($data['deliveries'] ?? false) {
|
||||
@@ -113,7 +124,9 @@ class Customers
|
||||
unset($data['invoices']);
|
||||
}
|
||||
$customer = self::store($data);
|
||||
$customer->sale_channels()->sync($saleChannels);
|
||||
if ($saleChannels !== null) {
|
||||
$customer->sale_channels()->sync($saleChannels);
|
||||
}
|
||||
CustomerAddresses::storeByCustomer($customer, $data2);
|
||||
|
||||
return $customer->id;
|
||||
|
||||
@@ -17,12 +17,15 @@ class InvoicePDF
|
||||
public static function get($id)
|
||||
{
|
||||
$invoice = Invoices::getFull($id);
|
||||
$customFields = [];
|
||||
if ($orderRef = optional($invoice->order)->ref) {
|
||||
$customFields['order number'] = $orderRef;
|
||||
}
|
||||
|
||||
$customer = new Party([
|
||||
'name' => $invoice->customer->name,
|
||||
'name' => optional($invoice->customer)->name ?? __('Client inconnu'),
|
||||
'address' => self::makeAddress($invoice->address),
|
||||
'custom_fields' => [
|
||||
'order number' => $invoice->order->ref,
|
||||
],
|
||||
'custom_fields' => $customFields,
|
||||
]);
|
||||
|
||||
$items = self::makeItems($invoice->order->detail);
|
||||
@@ -48,7 +51,17 @@ class InvoicePDF
|
||||
|
||||
public static function makeAddress($address)
|
||||
{
|
||||
return $address->address.'<br>'.$address->zipcode.' '.$address->city;
|
||||
if (! $address) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$lines = array_filter([
|
||||
$address->address ?? '',
|
||||
$address->address2 ?? '',
|
||||
trim(($address->zipcode ?? '').' '.($address->city ?? '')),
|
||||
]);
|
||||
|
||||
return implode('<br>', $lines);
|
||||
}
|
||||
|
||||
public static function makeItems($details)
|
||||
|
||||
@@ -1,8 +1,34 @@
|
||||
// Simple notification helper used by blade templates (fallback to Bootstrap alerts)
|
||||
window.growl = function(message, type) {
|
||||
var alertTypes = {
|
||||
success: 'alert-success',
|
||||
error: 'alert-danger',
|
||||
warning: 'alert-warning',
|
||||
info: 'alert-info'
|
||||
};
|
||||
var cssClass = alertTypes[type] || alertTypes.info;
|
||||
var $container = $('#growl-container');
|
||||
|
||||
if (!$container.length) {
|
||||
$container = $('<div id="growl-container" class="growl-container position-fixed w-100" style="top: 1rem; left: 0; z-index: 1080; pointer-events: none;"></div>');
|
||||
$('body').append($container);
|
||||
}
|
||||
|
||||
var $alert = $('<div class="alert ' + cssClass + ' alert-dismissible fade show mx-auto shadow" role="alert" style="max-width: 420px; pointer-events: all;"></div>');
|
||||
$alert.append($('<span></span>').text(message));
|
||||
$alert.append('<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>');
|
||||
$container.append($alert);
|
||||
|
||||
setTimeout(function() {
|
||||
$alert.alert('close');
|
||||
}, 4000);
|
||||
};
|
||||
|
||||
// Prevent closing from click inside dropdown
|
||||
$(document).on('click', '.dropdown-menu', function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
|
||||
// make it as accordion for smaller screens
|
||||
if ($(window).width() < 992) {
|
||||
$('.dropdown-menu a').click(function(e) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
'prefix' => 'deliveries',
|
||||
'addresses' => $customer['delivery_addresses'],
|
||||
'with_name' => true,
|
||||
'selected' => $customer['delivery_address_id'] ?? null,
|
||||
])
|
||||
</x-card>
|
||||
|
||||
@@ -32,6 +33,7 @@
|
||||
'prefix' => 'invoices',
|
||||
'addresses' => $customer['invoice_addresses'],
|
||||
'with_name' => true,
|
||||
'selected' => $customer['invoice_address_id'] ?? null,
|
||||
])
|
||||
</x-card>
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<div class="row mt-3 address-row" data-address-id="{{ $address['id'] }}">
|
||||
<div class="col-1">
|
||||
@php
|
||||
$inputName = isset($prefix) && $prefix ? $prefix.'[address_id]' : 'address_id';
|
||||
$currentValue = $selected ?? null;
|
||||
@endphp
|
||||
<x-form.radios.icheck name="{{ $inputName }}" val="{{ $address['id'] }}"
|
||||
:value="$currentValue" id="address_{{ $address['id'] }}" />
|
||||
</div>
|
||||
<div class="col-10">
|
||||
@if ($with_name ?? false)
|
||||
{{ $address['name'] ?? '' }}<br />
|
||||
@endif
|
||||
{{ $address['address'] }}<br />
|
||||
@if (! empty($address['address2']))
|
||||
{{ $address['address2'] }}<br />
|
||||
@endif
|
||||
{{ $address['zipcode'] }} {{ $address['city'] }}
|
||||
</div>
|
||||
<div class="col-1 text-right">
|
||||
<a class="text-danger" href="{{ route('Shop.Customers.delete_address', ['id' => $address['id']]) }}">
|
||||
<i class="fa fa-trash" data-id="{{ $address['id'] }}"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,26 +1,13 @@
|
||||
@foreach ($addresses ?? [] as $address)
|
||||
<div class="row mt-3">
|
||||
<div class="col-1">
|
||||
<x-form.radios.icheck name="@if ($prefix ?? false) {{ $prefix }} . '[]' @endif address_id"
|
||||
val="{{ $address['id'] }}" id="address_{{ $address['id'] }}" />
|
||||
</div>
|
||||
<div class="col-10">
|
||||
@if ($with_name ?? false)
|
||||
{{ $address['name'] }}<br />
|
||||
@endif
|
||||
{{ $address['address'] }}<br />
|
||||
@if ($address['address2'])
|
||||
{{ $address['address2'] }}<br />
|
||||
@endif
|
||||
{{ $address['zipcode'] }} {{ $address['city'] }}
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<a href="{{ route('Shop.Customers.delete_address') }}/{{ $address['id'] }}">
|
||||
<i class="fa fa-trash" class="delete" data-id="{{ $address['id'] }}"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
<div id="addresses_list_{{ $prefix }}" class="addresses-list">
|
||||
@foreach ($addresses ?? [] as $address)
|
||||
@include('Shop.Customers.partials.address_item', [
|
||||
'address' => $address,
|
||||
'prefix' => $prefix ?? null,
|
||||
'with_name' => $with_name ?? false,
|
||||
'selected' => $selected ?? null,
|
||||
])
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div id="add_address_container_{{ $prefix }}" class="green-dark d-none mb-3 mt-3">
|
||||
<x-card classBody="bg-green-dark yellow" title="Nouvelle adresse" classTitle="h4">
|
||||
@@ -31,6 +18,18 @@
|
||||
'label' => 'Adresse',
|
||||
'customer' => [],
|
||||
])
|
||||
<div class="row mt-3">
|
||||
<div class="col-md-6 mb-2">
|
||||
<x-form.button id="save_address_{{ $prefix }}" class="btn-success btn-sm btn-block"
|
||||
icon="fa-save" txt="Enregistrer cette adresse"
|
||||
:metadata="'data-prefix='.$prefix" />
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<x-form.button id="cancel_address_{{ $prefix }}" class="btn-outline-light btn-sm btn-block"
|
||||
icon="fa-times" txt="Annuler"
|
||||
:metadata="'data-prefix='.$prefix" />
|
||||
</div>
|
||||
</div>
|
||||
</x-card>
|
||||
</div>
|
||||
|
||||
@@ -43,8 +42,71 @@
|
||||
|
||||
@push('js')
|
||||
<script>
|
||||
$('#add_address_{{ $prefix }}').click(function() {
|
||||
$('#add_address_container_{{ $prefix }}').toggleClass('d-none');
|
||||
})
|
||||
(function() {
|
||||
var prefix = '{{ $prefix }}';
|
||||
var $formContainer = $('#add_address_container_{{ $prefix }}');
|
||||
var $list = $('#addresses_list_{{ $prefix }}');
|
||||
var storeUrl = '{{ route('Shop.Customers.address.store') }}';
|
||||
|
||||
var $toggleBtn = $('#add_address_{{ $prefix }}');
|
||||
|
||||
$toggleBtn.on('click', function() {
|
||||
var isHidden = $formContainer.hasClass('d-none');
|
||||
if (isHidden) {
|
||||
$formContainer.removeClass('d-none');
|
||||
$toggleBtn.prop('disabled', true);
|
||||
}
|
||||
});
|
||||
|
||||
$('#cancel_address_{{ $prefix }}').on('click', function() {
|
||||
$formContainer.addClass('d-none');
|
||||
$formContainer.find('input[type="text"]').val('');
|
||||
$toggleBtn.prop('disabled', false);
|
||||
});
|
||||
|
||||
$('#save_address_{{ $prefix }}').on('click', function() {
|
||||
const data = $formContainer.find(':input').serialize();
|
||||
$.ajax({
|
||||
url: storeUrl,
|
||||
method: 'POST',
|
||||
data: data + '&prefix=' + prefix,
|
||||
success: function(response) {
|
||||
if (response.html) {
|
||||
$list.append(response.html);
|
||||
}
|
||||
$formContainer.addClass('d-none');
|
||||
$formContainer.find('input[type="text"]').val('');
|
||||
$toggleBtn.prop('disabled', false);
|
||||
if (response.id) {
|
||||
const $newRadio = $list.find('#address_' + response.id);
|
||||
$list.find('input[type="radio"]').not($newRadio).prop('checked', false);
|
||||
$newRadio.prop('checked', true);
|
||||
}
|
||||
if (typeof $.fn.iCheck === 'function') {
|
||||
$list.find('input[type="radio"]').iCheck('destroy');
|
||||
if (typeof initIcheck === 'function') {
|
||||
initIcheck('#addresses_list_{{ $prefix }} input[type="radio"]');
|
||||
if (response.id) {
|
||||
$list.find('#address_' + response.id).iCheck('check');
|
||||
}
|
||||
}
|
||||
}
|
||||
const message = response.message || '{{ __('Adresse enregistrée.') }}';
|
||||
if (typeof growl === 'function') {
|
||||
growl(message, 'success');
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
let message = '{{ __('Une erreur est survenue lors de l\'enregistrement de l\'adresse.') }}';
|
||||
if (xhr.responseJSON && xhr.responseJSON.message) {
|
||||
message = xhr.responseJSON.message;
|
||||
}
|
||||
if (typeof growl === 'function') {
|
||||
growl(message, 'error');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@@ -16,11 +16,27 @@
|
||||
@push('js')
|
||||
<script>
|
||||
$(function() {
|
||||
const articleShowUrlTemplate = "{{ route('Shop.Articles.show', ['id' => '__ARTICLE_ID__']) }}";
|
||||
|
||||
$('#search-general .fa-search').click(function() {
|
||||
$('#search-general').submit();
|
||||
});
|
||||
|
||||
initAutocomplete('#search_name');
|
||||
function redirectToArticle(item, evt) {
|
||||
if (!item || typeof item.value === 'undefined' || item.value === null || item.value === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
}
|
||||
|
||||
const targetUrl = articleShowUrlTemplate.replace('__ARTICLE_ID__', item.value);
|
||||
window.location.href = targetUrl;
|
||||
}
|
||||
|
||||
initAutocomplete('#search_name', redirectToArticle);
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
var id = item.value;
|
||||
$('#' + field).val(id);
|
||||
|
||||
if (typeof(callback) != 'undefined') {
|
||||
var c = callback + '(' + id + ')';
|
||||
eval(c);
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(this, item, evt);
|
||||
} else if (typeof callback === 'string' && callback.length && typeof window[callback] === 'function') {
|
||||
window[callback].call(this, item, evt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,5 +7,6 @@ Route::prefix('Clients')->name('Customers.')->group(function () {
|
||||
Route::get('edit', 'CustomerController@edit')->name('edit');
|
||||
Route::post('storeProfileAjax', 'CustomerController@storeProfileAjax')->name('storeProfileAjax');
|
||||
Route::post('store', 'CustomerController@store')->name('store');
|
||||
Route::get('delete_address/{$id?}', 'CustomerController@delete_address')->name('delete_address');
|
||||
Route::post('address', 'CustomerController@storeAddress')->name('address.store');
|
||||
Route::get('delete_address/{id}', 'CustomerController@delete_address')->name('delete_address');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user