Create routes and views for customers and their addresses.
This commit is contained in:
66
app/Http/Controllers/Api/AddressController.php
Normal file
66
app/Http/Controllers/Api/AddressController.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Address;
|
||||
use App\Models\Customer;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class AddressController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(Customer $customer): JsonResponse
|
||||
{
|
||||
return response()->json($customer->addresses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request, Customer $customer): JsonResponse
|
||||
{
|
||||
$addressData = $request->validate([
|
||||
'name' => 'required|string',
|
||||
'email' => 'required|string|email',
|
||||
'phone' => 'string',
|
||||
'address' => 'string',
|
||||
'city' => 'string',
|
||||
'zip' => 'numeric',
|
||||
'is_address' => 'boolean',
|
||||
'is_delivery' => 'boolean',
|
||||
]);
|
||||
|
||||
if (isset($addressData['is_address']) && $addressData['is_address'] == 1) {
|
||||
$customer->addresses()->where('is_address', true)->update(['is_address' => false]);
|
||||
}
|
||||
|
||||
if (isset($addressData['is_delivery']) && $addressData['is_delivery'] == 1) {
|
||||
$customer->addresses()->where('is_delivery', true)->update(['is_delivery' => false]);
|
||||
}
|
||||
|
||||
$address = $customer->addresses()->create($addressData);
|
||||
return response()->json($address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(Address $address): JsonResponse
|
||||
{
|
||||
return response()->json($address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Address $address): JsonResponse
|
||||
{
|
||||
$address->delete();
|
||||
|
||||
return response()->json(null, 204);
|
||||
}
|
||||
}
|
||||
69
app/Http/Controllers/Api/CustomerController.php
Normal file
69
app/Http/Controllers/Api/CustomerController.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Customer;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class CustomerController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
return response()->json(Customer::with(['address', 'delivery'])->orderBy('name')->get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$customerData = $request->validate([
|
||||
'name' => 'required|string',
|
||||
'email' => 'required|string|email|unique:customers'
|
||||
]);
|
||||
|
||||
$customer = new Customer($customerData);
|
||||
$customer->save();
|
||||
|
||||
return response()->json($customer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(Customer $customer): JsonResponse
|
||||
{
|
||||
return response()->json($customer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Customer $customer): JsonResponse
|
||||
{
|
||||
$customerData = $request->validate([
|
||||
'name' => 'required|string',
|
||||
'email' => ['required', 'string', 'email', Rule::unique('customers')->ignore($customer->id)],
|
||||
]);
|
||||
|
||||
$customer->update($customerData);
|
||||
|
||||
return response()->json($customer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Customer $customer): JsonResponse
|
||||
{
|
||||
$customer->delete();
|
||||
|
||||
return response()->json(null, 204);
|
||||
}
|
||||
}
|
||||
34
app/Http/Controllers/CustomerController.php
Normal file
34
app/Http/Controllers/CustomerController.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Customer;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
class CustomerController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
return view('customer.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('customer.create');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(Customer $customer): View
|
||||
{
|
||||
return view('customer.edit', ['customer' => $customer->load(['addresses'])]);
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,20 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
class Address extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'is_address',
|
||||
'is_delivery',
|
||||
'name',
|
||||
'email',
|
||||
'phone',
|
||||
'address',
|
||||
'city',
|
||||
'state',
|
||||
'country',
|
||||
'zip',
|
||||
|
||||
];
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,9 +3,77 @@
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class Customer extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are appended with attribute getters.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $appends = [
|
||||
'created',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the created_at attribute in local time format.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCreatedAttribute(): string
|
||||
{
|
||||
return $this->created_at->format('d.m.Y');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the invoice address.
|
||||
*
|
||||
* @return HasOne
|
||||
*/
|
||||
public function address(): HasOne
|
||||
{
|
||||
return $this->hasOne(Address::class)->ofMany([],
|
||||
function (Builder $query) {
|
||||
$query->where('is_address', '=', true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the delivery address.
|
||||
*
|
||||
* @return HasOne
|
||||
*/
|
||||
public function delivery(): HasOne
|
||||
{
|
||||
return $this->hasOne(Address::class)->ofMany([],
|
||||
function (Builder $query) {
|
||||
$query->where('is_delivery', '=', true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all customer's addresses.
|
||||
*
|
||||
* @return HasMany
|
||||
*/
|
||||
public function addresses(): HasMany
|
||||
{
|
||||
return $this->hasMany(Address::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ return new class extends Migration {
|
||||
{
|
||||
Schema::create('addresses', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained();
|
||||
$table->foreignId('customer_id')->constrained();
|
||||
|
||||
$table->string('name');
|
||||
$table->string('email')->nullable();
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('addresses', function (Blueprint $table) {
|
||||
$table->boolean('is_address')->default(false)->after('customer_id');
|
||||
$table->boolean('is_delivery')->default(false)->after('is_address');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('addresses', function (Blueprint $table) {
|
||||
$table->dropColumn('is_address');
|
||||
$table->dropColumn('is_delivery');
|
||||
});
|
||||
}
|
||||
};
|
||||
4
lang/de.json
Normal file
4
lang/de.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"(and :count more error)": "(und :count weiterer Fehler)",
|
||||
"(and :count more errors)": "(und :count weitere Fehler)"
|
||||
}
|
||||
@@ -16,6 +16,10 @@ return [
|
||||
'Name' => 'Name',
|
||||
'Email' => 'Email',
|
||||
'Password' => 'Passwort',
|
||||
'Phone' => 'Telefon',
|
||||
'Address' => 'Adresse',
|
||||
'Zip Code' => 'Postleitzahl',
|
||||
'City' => 'Stadt',
|
||||
'You\'re logged in!' => 'Du bist angemeldet!',
|
||||
'Confirm' => 'Bestätigen',
|
||||
'Email Password Reset Link' => 'Email Passwort-Reset Link',
|
||||
|
||||
@@ -13,10 +13,21 @@ return [
|
||||
|
||||
'Customers' => 'Kunden',
|
||||
'Add new customer' => 'Neuer Kunde',
|
||||
'Add new customer by clicking add' => 'Neuen Kunde erstellen',
|
||||
'Edit existing customer' => 'Bestehenden Kunden bearbeiten',
|
||||
'Add new customer by clicking add' => 'Durch Klick auf "Anlegen" neuen Kunden erstellen',
|
||||
'Existing customers' => 'Bestehende Kunden',
|
||||
'Create new customer' => 'Neuen Kunden anlegen',
|
||||
'New customer' => 'Neuer Kunde',
|
||||
'Enter your customer\'s information and email address.' => 'Gib die Informationen und die E-Mail-Adresse des Kunden ein.'
|
||||
'Enter your customer\'s information and email address.' => 'Gib die Informationen und die E-Mail-Adresse des Kunden ein.',
|
||||
'Invoice Address' => 'Rechnungsadresse',
|
||||
'Delivery Address' => 'Versandadresse',
|
||||
'Other Address' => 'Sonstige Adresse',
|
||||
'Invoice and Delivery Address' => 'Rechnungs- und Versandadresse',
|
||||
'Existing addresses' => 'Bestehende Adressen',
|
||||
'New address' => 'Neue Adresse',
|
||||
'Delete Address' => 'Adresse löschen',
|
||||
'Are you sure you want to delete the address?' => 'Sicher, dass die Adresse gelöscht werden soll?',
|
||||
'Once the address is deleted, all the ressources and data will be permanently deleted.' => 'Sobald die Adresse gelöscht wird, werden alle Ressourcen und Daten dauerhaft gelöscht.',
|
||||
'Enter your customer\'s address.' => 'Gib die Addresse des Kunden ein.',
|
||||
|
||||
];
|
||||
|
||||
16
resources/views/components/address-card.blade.php
Normal file
16
resources/views/components/address-card.blade.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<div x-show="address.is_address && address.is_delivery"
|
||||
class="text-lg font-medium text-gray-900 dark:text-gray-100">{{ __('customer.Invoice and Delivery Address') }}</div>
|
||||
<div x-show="address.is_address && !address.is_delivery"
|
||||
class="text-lg font-medium text-gray-900 dark:text-gray-100">{{ __('customer.Invoice Address') }}</div>
|
||||
<div x-show="address.is_delivery && !address.is_address"
|
||||
class="text-lg font-medium text-gray-900 dark:text-gray-100">{{ __('customer.Delivery Address') }}</div>
|
||||
<div x-show="!address.is_delivery && !address.is_address"
|
||||
class="text-lg font-medium text-gray-900 dark:text-gray-100">{{ __('customer.Other Address') }}</div>
|
||||
<div x-text="address.name"></div>
|
||||
<div x-text="address.address"></div>
|
||||
<div class="flex flex-row">
|
||||
<div class="mr-2" x-text="address.zip"></div>
|
||||
<div x-text="address.city"></div>
|
||||
</div>
|
||||
<div x-text="address.phone"></div>
|
||||
<div x-text="address.email"></div>
|
||||
82
resources/views/customer/create.blade.php
Normal file
82
resources/views/customer/create.blade.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
|
||||
{{ __('customer.Create new customer') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12" x-data="customerForm()">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
|
||||
<!-- Customer data -->
|
||||
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
|
||||
<div class="max-w-xl">
|
||||
<section>
|
||||
<header>
|
||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
|
||||
{{ __('customer.New customer') }}
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ __("customer.Enter your customer's information and email address.") }}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<form class="mt-6 space-y-6" @submit.prevent="">
|
||||
<p class="text-red-600 font-bold" x-text="message" x-show="error"></p>
|
||||
|
||||
<div>
|
||||
<x-input-label for="name" :value="__('common.Name')"/>
|
||||
<x-text-input id="name" name="name" type="text" class="mt-1 block w-full"
|
||||
:value="old('name')" required autofocus autocomplete="name"
|
||||
x-model="customer.name"/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<x-input-label for="email" :value="__('common.Email')"/>
|
||||
<x-text-input id="email" name="email" type="email" class="mt-1 block w-full"
|
||||
:value="old('email')" required autocomplete="username"
|
||||
x-model="customer.email"/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<x-primary-button @click="submit">{{ __('form.Save') }}</x-primary-button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</x-app-layout>
|
||||
|
||||
<script>
|
||||
function customerForm() {
|
||||
return {
|
||||
customer: {
|
||||
name: '',
|
||||
email: '',
|
||||
},
|
||||
|
||||
error: false,
|
||||
message: '',
|
||||
|
||||
submit() {
|
||||
let vm = this;
|
||||
|
||||
axios.post('/customer', this.customer)
|
||||
.then(function (response) {
|
||||
window.location.href = '/customer/' + response.data.id + '/edit';
|
||||
})
|
||||
.catch(function (error) {
|
||||
vm.error = true;
|
||||
vm.message = error.response.data.message;
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
286
resources/views/customer/edit.blade.php
Normal file
286
resources/views/customer/edit.blade.php
Normal file
@@ -0,0 +1,286 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
|
||||
{{ __('customer.Create new customer') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12" x-data="customerForm()">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
|
||||
<!-- Customer data -->
|
||||
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
|
||||
<div class="max-w-xl">
|
||||
<section>
|
||||
<header>
|
||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
|
||||
{{ __('customer.New customer') }}
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ __("customer.Enter your customer's information and email address.") }}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<form class="mt-6 space-y-6" @submit.prevent="" x-bind="customer">
|
||||
|
||||
<p class="text-red-600 font-bold" x-text="customer_message" x-show="customer_error"></p>
|
||||
<p x-show="customer_success" x-transition
|
||||
class="text-sm text-green-600 dark:text-green-400">{{ __('form.Saved') }}</p>
|
||||
|
||||
<div>
|
||||
<x-input-label for="name" :value="__('common.Name')"/>
|
||||
<x-text-input id="name" name="name" type="text" class="mt-1 block w-full"
|
||||
:value="old('name')" required autofocus autocomplete="name"
|
||||
x-model="customer.name"/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<x-input-label for="email" :value="__('common.Email')"/>
|
||||
<x-text-input id="email" name="email" type="email" class="mt-1 block w-full"
|
||||
:value="old('email')" required autocomplete="username"
|
||||
x-model="customer.email"/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<x-primary-button @click="updateCustomer">{{ __('form.Save') }}</x-primary-button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Existing addresses -->
|
||||
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg" x-bind="addresses">
|
||||
<div class="max-w">
|
||||
<section>
|
||||
<header>
|
||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
|
||||
{{ __('customer.Existing addresses') }}
|
||||
</h2>
|
||||
</header>
|
||||
<div class="grid grid-cols-3">
|
||||
<template x-for="address in addresses" :key="address.id">
|
||||
<div>
|
||||
<div class="flex flex-col p-8 pb-0">
|
||||
<x-address-card/>
|
||||
</div>
|
||||
<x-danger-button
|
||||
x-show="!address.is_delivery && !address.is_address"
|
||||
class="ml-8"
|
||||
x-data=""
|
||||
x-on:click.prevent="delete_id = address.id;$dispatch('open-modal', 'confirm-user-deletion')"
|
||||
>{{ __('customer.Delete Address') }}</x-danger-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Address data -->
|
||||
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg" x-bind="address">
|
||||
|
||||
<div class="max-w-xl">
|
||||
<section>
|
||||
<header>
|
||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
|
||||
{{ __('customer.New address') }}
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ __("customer.Enter your customer's address.") }}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<form class="mt-6 space-y-6" @submit.prevent="">
|
||||
|
||||
<p class="text-red-600 font-bold" x-text="address_message" x-show="address_error"></p>
|
||||
<p x-show="address_success" x-transition
|
||||
class="text-sm text-green-600 dark:text-green-400">{{ __('form.Saved') }}</p>
|
||||
|
||||
<div>
|
||||
<x-input-label for="address[name]" :value="__('common.Name')"/>
|
||||
<x-text-input id="address[name]" name="address[name]" type="text"
|
||||
class="mt-1 block w-full" :value="old('name')" required autofocus
|
||||
autocomplete="name" x-model="address.name"/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<x-input-label for="address[email]" :value="__('common.Email')"/>
|
||||
<x-text-input id="address[email]" name="address[email]" type="email"
|
||||
class="mt-1 block w-full" :value="old('email')" required
|
||||
autocomplete="username" x-model="address.email"/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<x-input-label for="address[phone]" :value="__('common.Phone')"/>
|
||||
<x-text-input id="address[phone]" name="address[phone]" type="text"
|
||||
class="mt-1 block w-full" :value="old('phone')" autocomplete="phone"
|
||||
x-model="address.phone"/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<x-input-label for="address[address]" :value="__('common.Address')"/>
|
||||
<x-text-input id="address[address]" name="address[address]" type="text"
|
||||
class="mt-1 block w-full" :value="old('address')" autocomplete="address"
|
||||
x-model="address.address"/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row space-x-8">
|
||||
<div class="w-1/4">
|
||||
<x-input-label for="address[zip]" :value="__('common.Zip Code')"/>
|
||||
<x-text-input id="address[zip]" name="address[zip]" type="text"
|
||||
class="mt-1 block w-full" :value="old('zip')" autocomplete="zip"
|
||||
x-model="address.zip"/>
|
||||
</div>
|
||||
<div class="w-3/4">
|
||||
<x-input-label for="address[city]" :value="__('common.City')"/>
|
||||
<x-text-input id="address[city]" name="address[city]" type="text"
|
||||
class="mt-1 block w-full" :value="old('city')" autocomplete="city"
|
||||
x-model="address.city"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row space-x-8">
|
||||
<x-input-label class="w-1/4" for="address[is_address]" :value="__('customer.Invoice Address')"/>
|
||||
<input type="hidden" name="address[is_address]" value="0" />
|
||||
<x-text-input id="address[is_address]" name="address[is_address]" type="checkbox"
|
||||
class="mt-1" :value="old('is_address')"
|
||||
x-model="address.is_address"/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row space-x-8">
|
||||
<x-input-label class="w-1/4" for="address[is_delivery]" :value="__('customer.Delivery Address')"/>
|
||||
<input type="hidden" name="address[is_delivery]" value="0" />
|
||||
<x-text-input id="address[is_delivery]" name="address[is_delivery]" type="checkbox"
|
||||
class="mt-1" :value="old('is_delivery')"
|
||||
x-model="address.is_delivery"/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<x-primary-button @click="createAddress">{{ __('form.Save') }}</x-primary-button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal for address deletion -->
|
||||
<x-modal name="confirm-user-deletion" :show="$errors->userDeletion->isNotEmpty()" focusable>
|
||||
<form class="p-6" @submit.prevent="">
|
||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
|
||||
{{ __('customer.Are you sure you want to delete the address?') }}
|
||||
</h2>
|
||||
|
||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ __('customer.Once the address is deleted, all the ressources and data will be permanently deleted.') }}
|
||||
</p>
|
||||
|
||||
<div class="mt-6 flex justify-end">
|
||||
<x-secondary-button x-on:click="$dispatch('close')">
|
||||
{{ __('form.Cancel') }}
|
||||
</x-secondary-button>
|
||||
|
||||
<x-danger-button class="ms-3" x-on:click="deleteAddress();$dispatch('close')">
|
||||
{{ __('customer.Delete Address') }}
|
||||
</x-danger-button>
|
||||
</div>
|
||||
</form>
|
||||
</x-modal>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</x-app-layout>
|
||||
|
||||
<script>
|
||||
|
||||
function customerForm() {
|
||||
return {
|
||||
customer: {},
|
||||
customer_id: {{ $customer->id }},
|
||||
addresses: {},
|
||||
address: {},
|
||||
|
||||
delete_id: 0,
|
||||
|
||||
customer_error: false,
|
||||
customer_message: '',
|
||||
customer_success: false,
|
||||
|
||||
address_error: false,
|
||||
address_message: '',
|
||||
address_success: false,
|
||||
|
||||
init() {
|
||||
this.getCustomer();
|
||||
this.getAddresses();
|
||||
},
|
||||
|
||||
updateCustomer() {
|
||||
let vm = this;
|
||||
axios.put('/customer/' + this.customer_id, this.customer)
|
||||
.then(function(response) {
|
||||
vm.customer_success = true;
|
||||
}).catch(function (error) {
|
||||
vm.customer_error = true;
|
||||
vm.customer_message = error.response.data.message;
|
||||
})
|
||||
},
|
||||
|
||||
getCustomer() {
|
||||
let vm = this;
|
||||
|
||||
axios.get('/customer/' + this.customer_id)
|
||||
.then(function (response) {
|
||||
vm.customer = response.data;
|
||||
})
|
||||
.catch(function (error) {
|
||||
vm.customer_error = true;
|
||||
vm.customer_message = error.response.data.message;
|
||||
})
|
||||
},
|
||||
|
||||
getAddresses() {
|
||||
let vm = this;
|
||||
|
||||
axios.get('/customer/' + this.customer_id + '/address')
|
||||
.then(function (response) {
|
||||
vm.addresses = response.data;
|
||||
})
|
||||
.catch(function (error) {
|
||||
vm.address_error = true;
|
||||
vm.address_message = error.response.data.message;
|
||||
})
|
||||
},
|
||||
|
||||
createAddress() {
|
||||
let vm = this;
|
||||
|
||||
axios.post('/customer/' + this.customer.id + '/address', this.address)
|
||||
.then(function (response) {
|
||||
vm.addresses.push(response.data);
|
||||
vm.address_success = true;
|
||||
vm.getAddresses();
|
||||
})
|
||||
.catch(function (error) {
|
||||
vm.address_error = true;
|
||||
vm.address_message = error.response.data.message;
|
||||
})
|
||||
},
|
||||
|
||||
deleteAddress() {
|
||||
let vm = this;
|
||||
|
||||
axios.delete('/address/' + this.delete_id)
|
||||
.then(function (response) {
|
||||
let removeIndex = vm.addresses.map(item => item.id).indexOf(vm.delete_id);
|
||||
vm.addresses.splice(removeIndex, 1);
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
102
resources/views/customer/index.blade.php
Normal file
102
resources/views/customer/index.blade.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
|
||||
{{ __('customer.Customers') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
|
||||
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
|
||||
<div class="max-w-xl">
|
||||
<section>
|
||||
<header>
|
||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
|
||||
{{ __('customer.Add new customer') }}
|
||||
</h2>
|
||||
|
||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ __("customer.Add new customer by clicking add") }}
|
||||
</p>
|
||||
|
||||
</header>
|
||||
<a class="mt-6 inline-block" href="{{ route('customer.create') }}"><x-primary-button>{{ __('form.Add') }}</x-primary-button></a>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
|
||||
<div class="max-w" x-data="{ customers: []}"
|
||||
x-init="customers = await fetchCustomers().then((data) => data );">
|
||||
<section>
|
||||
<header>
|
||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
|
||||
{{ __('customer.Existing customers') }}
|
||||
</h2>
|
||||
</header>
|
||||
|
||||
<summary class="cursor-pointer grid grid-cols-3 mt-4">
|
||||
<div class="font-bold border-b-2">Name</div>
|
||||
<div class="font-bold border-b-2">Email</div>
|
||||
<div class="font-bold border-b-2">Erstellt am</div>
|
||||
</summary>
|
||||
|
||||
<template x-for="customer in customers">
|
||||
<details class=" even:bg-gray-100 odd:bg-white">
|
||||
<summary class="cursor-pointer grid grid-cols-3">
|
||||
<div x-text="customer.name"></div>
|
||||
<div x-text="customer.email"></div>
|
||||
<div x-text="customer.created"></div>
|
||||
</summary>
|
||||
|
||||
<div class="flex flex-row">
|
||||
<template x-if="customer.address">
|
||||
<div class="flex flex-col p-8 w-1/3">
|
||||
<div class="text-lg font-medium text-gray-900 dark:text-gray-100">{{ __('customer.Invoice Address') }}</div>
|
||||
<div x-text="customer.address.name"></div>
|
||||
<div x-text="customer.address.address"></div>
|
||||
<div x-text="customer.address.zip +' ' + customer.address.city"></div>
|
||||
<div x-text="customer.address.phone"></div>
|
||||
<div x-text="customer.address.email"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="customer.delivery">
|
||||
<div class="flex flex-col p-8 w-1/3">
|
||||
<div class="text-lg font-medium text-gray-900 dark:text-gray-100">{{ __('customer.Delivery Address') }}</div>
|
||||
<div x-text="customer.delivery.name"></div>
|
||||
<div x-text="customer.delivery.address"></div>
|
||||
<div x-text="customer.delivery.zip +' ' + customer.delivery.city"></div>
|
||||
<div x-text="customer.delivery.phone"></div>
|
||||
<div x-text="customer.delivery.email"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a class="ml-8 mb-8 inline-block" x-bind:href="'/customer/' + customer.id + '/edit'"><x-primary-button>{{ __('form.Edit') }}</x-primary-button></a>
|
||||
</div>
|
||||
</details>
|
||||
</template>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</x-app-layout>
|
||||
|
||||
<script>
|
||||
let fetchCustomers = async () => {
|
||||
return await new Promise((resolve, reject) => {
|
||||
axios.get('/customer')
|
||||
.then(function (response) {
|
||||
resolve(response.data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\Api\AddressController;
|
||||
use App\Http\Controllers\Api\AuthController;
|
||||
use App\Http\Controllers\Api\CustomerController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
@@ -16,6 +18,8 @@ Route::group(['as' => 'api.'], function () {
|
||||
return $request->user();
|
||||
});
|
||||
|
||||
Route::apiResource('/customer', CustomerController::class);
|
||||
Route::apiResource('/customer.address', AddressController::class)->shallow()->except(['update']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\CustomerController;
|
||||
use App\Http\Controllers\ProfileController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
@@ -15,6 +16,8 @@ Route::middleware('auth')->group(function () {
|
||||
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
|
||||
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
|
||||
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
|
||||
|
||||
Route::resource('/customer', CustomerController::class)->only(['index', 'create', 'edit']);
|
||||
});
|
||||
|
||||
require __DIR__.'/auth.php';
|
||||
|
||||
Reference in New Issue
Block a user