diff --git a/app/Http/Controllers/CarController.php b/app/Http/Controllers/CarController.php index 407307e..671ac6c 100644 --- a/app/Http/Controllers/CarController.php +++ b/app/Http/Controllers/CarController.php @@ -14,7 +14,31 @@ class CarController extends Controller */ public function index() { - // + return Inertia::render('Cars/Index', [ + 'filters' => Request::all('search', 'trashed'), + 'cars' => Car::all() + ->orderByName() + ->filter(Request::only('search', 'trashed')) + ->paginate() + ->withQueryString() + ->through(function ($car) { + return [ + 'id' => $car->id, + 'stammnummer' => $car->stammnummer, + 'vin' => $car->vin, + 'bought_at' => $car->bought_at, + 'buy_price' => $car->buy_price, + 'seller' => $car->seller->only('name'); + 'buyer' => $car->buyer->only('name'); + 'car_model' => $car->carModel->only('name'), + 'name' => $car->name, + 'phone' => $car->phone, + 'zipcode' => $car->city, + 'city' => $car->city, + 'deleted_at' => $car->deleted_at, + ]; + }), + ]); } /** @@ -24,7 +48,7 @@ class CarController extends Controller */ public function create() { - // + return Inertia::render('Cars/Create'); } /** @@ -80,6 +104,14 @@ class CarController extends Controller */ public function destroy(Car $car) { - // + $car->delete(); + return Redirect::back()->with('success', 'Auto gelöscht.'); + } + + public function restore(Car $car) + { + $car->restore(); + + return Redirect::back()->with('success', 'Auto wiederhergestellt.'); } } diff --git a/app/Http/Controllers/ContactController.php b/app/Http/Controllers/ContactController.php index 1d59fea..0524141 100644 --- a/app/Http/Controllers/ContactController.php +++ b/app/Http/Controllers/ContactController.php @@ -14,7 +14,24 @@ class ContactController extends Controller */ public function index() { - // + return Inertia::render('Contacts/Index', [ + 'filters' => Request::all('search', 'trashed'), + 'contacts' => Contact::all() + ->orderByName() + ->filter(Request::only('search', 'trashed')) + ->paginate() + ->withQueryString() + ->through(function ($contact) { + return [ + 'id' => $contact->id, + 'name' => $contact->name, + 'phone' => $contact->phone, + 'zipcode' => $contact->city, + 'city' => $contact->city, + 'deleted_at' => $contact->deleted_at, + ]; + }), + ]); } /** @@ -24,7 +41,7 @@ class ContactController extends Controller */ public function create() { - // + return Inertia::render('Contacts/Create'); } /** @@ -35,18 +52,21 @@ class ContactController extends Controller */ public function store(Request $request) { - // - } + Contact::create( + Request::validate([ + 'firstname' => ['required', 'max:75'], + 'lastname' => ['required', 'max:75'], + 'email' => ['nullable', 'max:75', 'email'], + 'phone' => ['max:75'], + 'address' => ['nullable', 'max:150'], + 'zipcode' => ['nullable', 'max:6'], + 'city' => ['nullable', 'max:75'], + 'country' => ['nullable', 'max:2'], + 'company' => ['nullable', 'max:75'], + ]) + ); - /** - * Display the specified resource. - * - * @param \App\Models\Contact $contact - * @return \Illuminate\Http\Response - */ - public function show(Contact $contact) - { - // + return Redirect::route('contacts')->with('success', 'Kontakt erstellt.'); } /** @@ -57,7 +77,20 @@ class ContactController extends Controller */ public function edit(Contact $contact) { - // + return Inertia::render('Contacts/Edit', [ + 'contact' => [ + 'id' => $contact->id, + 'firstname' => $contact->first_name, + 'lastname' => $contact->last_name, + 'email' => $contact->email, + 'phone' => $contact->phone, + 'address' => $contact->address, + 'zipcode' => $contact->postal_code, + 'city' => $contact->city, + 'country' => $contact->country, + 'deleted_at' => $contact->deleted_at, + ] + ]); } /** @@ -69,7 +102,21 @@ class ContactController extends Controller */ public function update(Request $request, Contact $contact) { - // + $contact->update( + Request::validate([ + 'firstname' => ['required', 'max:75'], + 'lastname' => ['required', 'max:75'], + 'email' => ['nullable', 'max:75', 'email'], + 'phone' => ['max:75'], + 'address' => ['nullable', 'max:150'], + 'zipcode' => ['nullable', 'max:6'], + 'city' => ['nullable', 'max:75'], + 'country' => ['nullable', 'max:2'], + 'company' => ['nullable', 'max:75'], + ]) + ); + + return Redirect::route('contacts')->with('success', 'Kontakt geändert.'); } /** @@ -80,6 +127,14 @@ class ContactController extends Controller */ public function destroy(Contact $contact) { - // + $contact->delete(); + return Redirect::back()->with('success', 'Kontakt gelöscht.'); + } + + public function restore(Contact $contact) + { + $contact->restore(); + + return Redirect::back()->with('success', 'Kontakt wiederhergestellt.'); } } diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index ff0e33f..ace7c1b 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -37,7 +37,22 @@ class HandleInertiaRequests extends Middleware public function share(Request $request) { return array_merge(parent::share($request), [ - // + 'auth' => function () use ($request) { + return [ + 'user' => $request->user() ? [ + 'id' => $request->user()->id, + 'firstname' => $request->user()->firstname, + 'lastname' => $request->user()->lastname, + 'email' => $request->user()->email, + ] : null, + ]; + }, + 'flash' => function () use ($request) { + return [ + 'success' => $request->session()->get('success'), + 'error' => $request->session()->get('error'), + ]; + }, ]); } } diff --git a/app/Models/Brand.php b/app/Models/Brand.php index d83e76f..bfe8cbe 100644 --- a/app/Models/Brand.php +++ b/app/Models/Brand.php @@ -9,7 +9,7 @@ class Brand extends Model { use HasFactory; - protected $fillable = ['brand']; + protected $fillable = ['name']; public function cars() { @@ -20,4 +20,17 @@ class Brand extends Model { return $this->hasMany(CarModel::class); } + + public function scopeFilter($query, array $filters) + { + $query->when($filters['search'] ?? null, function ($query, $search) { + $query->where('name', 'like', '%'.$search.'%'); + })->when($filters['trashed'] ?? null, function ($query, $trashed) { + if ($trashed === 'with') { + $query->withTrashed(); + } elseif ($trashed === 'only') { + $query->onlyTrashed(); + } + }); + } } diff --git a/app/Models/Car.php b/app/Models/Car.php index bcb4cdb..1194d4e 100644 --- a/app/Models/Car.php +++ b/app/Models/Car.php @@ -4,14 +4,15 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; class Car extends Model { - use HasFactory; + use HasFactory, softDeletes; protected $fillable = [ 'variation', - 'variation', + 'stammnummer', 'vin', 'colour', 'notes', @@ -23,6 +24,11 @@ class Car extends Model 'car_model_id' ]; + public function getNameAttribute() + { + return $this->brand->name . ' ' . $this->carModel->car_model . $this->variation ? '(' . $this->variation . ')' : ''; + } + public function brand() { return $this->hasOneThrough(Brand::class, CarModel::class); diff --git a/app/Models/Contact.php b/app/Models/Contact.php index 28d8324..a38083c 100644 --- a/app/Models/Contact.php +++ b/app/Models/Contact.php @@ -4,16 +4,17 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; class Contact extends Model { - use HasFactory; + use HasFactory, softDeletes; protected $fillable = [ 'firstname', 'lastname', 'phone', - 'street', + 'address', 'zip', 'city', 'country', @@ -22,6 +23,11 @@ class Contact extends Model 'notes', ]; + public function scopeOrderByName($query) + { + $query->orderBy('lastname')->orderBy('firstname'); + } + public function contracts() { return $this->hasMany(Contracts::class); @@ -36,4 +42,21 @@ class Contact extends Model { return $this->hasMany(Car::class, 'seller_id'); } + + public function scopeFilter($query, array $filters) + { + $query->when($filters['search'] ?? null, function ($query, $search) { + $query->where(function ($query) use ($search) { + $query->where('firstname', 'like', '%' . $search . '%') + ->orWhere('lastname', 'like', '%' . $search . '%') + ->orWhere('email', 'like', '%' . $search . '%'); + }); + })->when($filters['trashed'] ?? null, function ($query, $trashed) { + if ($trashed === 'with') { + $query->withTrashed(); + } elseif ($trashed === 'only') { + $query->onlyTrashed(); + } + }); + } } diff --git a/app/Models/Contract.php b/app/Models/Contract.php index 5a154a8..dfc9f2e 100644 --- a/app/Models/Contract.php +++ b/app/Models/Contract.php @@ -4,10 +4,11 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; class Contract extends Model { - use HasFactory; + use HasFactory, softDeletes; protected $fillable = [ 'sold_at', diff --git a/database/factories/BrandFactory.php b/database/factories/BrandFactory.php index b4ed7be..68d359d 100644 --- a/database/factories/BrandFactory.php +++ b/database/factories/BrandFactory.php @@ -22,7 +22,7 @@ class BrandFactory extends Factory public function definition() { return [ - 'brand' => $this->faker->word(), + 'name' => $this->faker->word(), ]; } } diff --git a/database/factories/CarModelFactory.php b/database/factories/CarModelFactory.php index f5c91dc..3fb0782 100644 --- a/database/factories/CarModelFactory.php +++ b/database/factories/CarModelFactory.php @@ -23,7 +23,7 @@ class CarModelFactory extends Factory public function definition() { return [ - 'car_model' => $this->faker->word(), + 'name' => $this->faker->word(), 'brand_id' => $this->faker->numberBetween(1, Brand::count()), ]; } diff --git a/database/factories/ContactFactory.php b/database/factories/ContactFactory.php index ba828f5..453e46f 100644 --- a/database/factories/ContactFactory.php +++ b/database/factories/ContactFactory.php @@ -29,8 +29,8 @@ class ContactFactory extends Factory 'firstname' => $this->faker->firstName(), 'lastname' => $this->faker->lastName(), 'phone' => $this->faker->PhoneNumber(), - 'street' => $this->faker->streetName(), - 'zip' => $this->faker->postcode(), + 'address' => $this->faker->streetName() . ' ' . $this->faker->buildingNumber(), + 'zip' => $this->faker->randomNumber(4, true), 'city' => $this->faker->city(), 'country' => $this->faker->countryCode(), 'company' => $this->faker->company(), diff --git a/database/migrations/2021_05_10_135028_create_brands_table.php b/database/migrations/2021_05_10_135028_create_brands_table.php index 41dfc6a..3488291 100644 --- a/database/migrations/2021_05_10_135028_create_brands_table.php +++ b/database/migrations/2021_05_10_135028_create_brands_table.php @@ -15,7 +15,7 @@ class CreateBrandsTable extends Migration { Schema::create('brands', function (Blueprint $table) { $table->id(); - $table->string('brand')->unique(); + $table->string('name')->unique(); $table->timestamps(); }); } diff --git a/database/migrations/2021_05_10_135156_create_contacts_table.php b/database/migrations/2021_05_10_135156_create_contacts_table.php index c7419ad..5c624b2 100644 --- a/database/migrations/2021_05_10_135156_create_contacts_table.php +++ b/database/migrations/2021_05_10_135156_create_contacts_table.php @@ -15,17 +15,18 @@ class CreateContactsTable extends Migration { Schema::create('contacts', function (Blueprint $table) { $table->id(); - $table->string('firstname')->nullable(); - $table->string('lastname')->nullable(); - $table->string('phone'); - $table->string('street')->nullable(); - $table->string('zip')->nullable(); - $table->string('city')->nullable(); - $table->string('country')->nullable(); - $table->string('company')->nullable(); - $table->string('email')->nullable(); + $table->string('firstname', 75)->nullable(); + $table->string('lastname', 75)->nullable(); + $table->string('phone', 75); + $table->string('address', 150)->nullable(); + $table->string('zip', 6)->nullable(); + $table->string('city', 75)->nullable(); + $table->string('country', 2)->nullable(); + $table->string('company', 75)->nullable(); + $table->string('email', 75)->nullable(); $table->text('notes')->nullable(); $table->timestamps(); + $table->softDeletes(); }); } diff --git a/database/migrations/2021_05_10_135208_create_car_models_table.php b/database/migrations/2021_05_10_135208_create_car_models_table.php index 5f151ac..e822992 100644 --- a/database/migrations/2021_05_10_135208_create_car_models_table.php +++ b/database/migrations/2021_05_10_135208_create_car_models_table.php @@ -15,7 +15,7 @@ class CreateCarModelsTable extends Migration { Schema::create('car_models', function (Blueprint $table) { $table->id(); - $table->string('car_model'); + $table->string('name'); $table->foreignId('brand_id') ->onUpdate('cascade') ->onDelete('cascade') diff --git a/database/migrations/2021_05_10_135957_create_cars_table.php b/database/migrations/2021_05_10_135957_create_cars_table.php index 091c5bd..e7a0a60 100644 --- a/database/migrations/2021_05_10_135957_create_cars_table.php +++ b/database/migrations/2021_05_10_135957_create_cars_table.php @@ -30,7 +30,7 @@ class CreateCarsTable extends Migration ->onDelete('cascade') ->constrained('car_models'); $table->timestamps(); - + $table->softDeletes(); $table->foreign('seller_contact_id')->references('id')->on('contacts'); }); } diff --git a/database/migrations/2021_05_10_144041_create_contracts_table.php b/database/migrations/2021_05_10_144041_create_contracts_table.php index 9ae7ea6..03331e5 100644 --- a/database/migrations/2021_05_10_144041_create_contracts_table.php +++ b/database/migrations/2021_05_10_144041_create_contracts_table.php @@ -29,6 +29,7 @@ class CreateContractsTable extends Migration $table->enum('insurance_type', InsuranceType::getValues()) ->default(InsuranceType::OptionOne); $table->timestamps(); + $table->softDeletes(); }); } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 7598bf3..d0fb787 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -4,6 +4,7 @@ namespace Database\Seeders; use Illuminate\Database\Seeder; use App\Models\User; +use App\Models\Team; use App\Models\Car; use App\Models\CarModel; use App\Models\Brand; @@ -23,6 +24,7 @@ class DatabaseSeeder extends Seeder public function run() { DB::statement('SET FOREIGN_KEY_CHECKS=0;'); + User::truncate(); CarPayment::truncate(); Contract::truncate(); Document::truncate(); @@ -31,9 +33,21 @@ class DatabaseSeeder extends Seeder CarModel::truncate(); Brand::truncate(); DB::statement('SET FOREIGN_KEY_CHECKS=1;'); - + + $user = User::factory()->create([ + 'name' => 'Nadim Salloum', + 'email' => 'hello@salloum.ch', + 'password' => bcrypt('abc123'), + ]); + + $team = Team::factory()->create([ + 'name' => 'Your SwissCar GmbH', + 'user_id' => $user->id, + 'personal_team' => false, + ]); + foreach ($this->getBrands() as $brand) { - Brand::create(['brand' => $brand]); + Brand::create(['name' => $brand]); } $carModels = CarModel::factory() diff --git a/public/js/app.js b/public/js/app.js index a1308c1..3c34515 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -47509,6 +47509,60 @@ _VerifyEmail_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__.default.__ /***/ }), +/***/ "./resources/js/Pages/Contacts/Create.vue": +/*!************************************************!*\ + !*** ./resources/js/Pages/Contacts/Create.vue ***! + \************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const script = {} +script.__file = "resources/js/Pages/Contacts/Create.vue" + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (script); + +/***/ }), + +/***/ "./resources/js/Pages/Contacts/Edit.vue": +/*!**********************************************!*\ + !*** ./resources/js/Pages/Contacts/Edit.vue ***! + \**********************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const script = {} +script.__file = "resources/js/Pages/Contacts/Edit.vue" + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (script); + +/***/ }), + +/***/ "./resources/js/Pages/Contacts/Index.vue": +/*!***********************************************!*\ + !*** ./resources/js/Pages/Contacts/Index.vue ***! + \***********************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const script = {} +script.__file = "resources/js/Pages/Contacts/Index.vue" + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (script); + +/***/ }), + /***/ "./resources/js/Pages/Dashboard.vue": /*!******************************************!*\ !*** ./resources/js/Pages/Dashboard.vue ***! @@ -50070,6 +50124,12 @@ var map = { "./Auth/TwoFactorChallenge.vue": "./resources/js/Pages/Auth/TwoFactorChallenge.vue", "./Auth/VerifyEmail": "./resources/js/Pages/Auth/VerifyEmail.vue", "./Auth/VerifyEmail.vue": "./resources/js/Pages/Auth/VerifyEmail.vue", + "./Contacts/Create": "./resources/js/Pages/Contacts/Create.vue", + "./Contacts/Create.vue": "./resources/js/Pages/Contacts/Create.vue", + "./Contacts/Edit": "./resources/js/Pages/Contacts/Edit.vue", + "./Contacts/Edit.vue": "./resources/js/Pages/Contacts/Edit.vue", + "./Contacts/Index": "./resources/js/Pages/Contacts/Index.vue", + "./Contacts/Index.vue": "./resources/js/Pages/Contacts/Index.vue", "./Dashboard": "./resources/js/Pages/Dashboard.vue", "./Dashboard.vue": "./resources/js/Pages/Dashboard.vue", "./PrivacyPolicy": "./resources/js/Pages/PrivacyPolicy.vue", diff --git a/resources/js/Pages/Contacts/Create.vue b/resources/js/Pages/Contacts/Create.vue new file mode 100644 index 0000000..e69de29 diff --git a/resources/js/Pages/Contacts/Edit.vue b/resources/js/Pages/Contacts/Edit.vue new file mode 100644 index 0000000..e69de29 diff --git a/resources/js/Pages/Contacts/Index.vue b/resources/js/Pages/Contacts/Index.vue new file mode 100644 index 0000000..4c40856 --- /dev/null +++ b/resources/js/Pages/Contacts/Index.vue @@ -0,0 +1,108 @@ + + + diff --git a/routes/web.php b/routes/web.php index 825eeed..5ffd5c8 100644 --- a/routes/web.php +++ b/routes/web.php @@ -27,3 +27,31 @@ Route::get('/', function () { Route::middleware(['auth:sanctum', 'verified'])->get('/dashboard', function () { return Inertia::render('Dashboard'); })->name('dashboard'); + +Route::get('contacts', [ContactsController::class, 'index']) + ->name('contacts') + ->middleware(['auth:sanctum', 'verified']); + +Route::get('contacts/create', [ContactsController::class, 'create']) + ->name('contacts.create') + ->middleware(['auth:sanctum', 'verified']); + +Route::post('contacts', [ContactsController::class, 'store']) + ->name('contacts.store') + ->middleware(['auth:sanctum', 'verified']); + +Route::get('contacts/{contact}/edit', [ContactsController::class, 'edit']) + ->name('contacts.edit') + ->middleware(['auth:sanctum', 'verified']); + +Route::put('contacts/{contact}', [ContactsController::class, 'update']) + ->name('contacts.update') + ->middleware(['auth:sanctum', 'verified']); + +Route::delete('contacts/{contact}', [ContactsController::class, 'destroy']) + ->name('contacts.destroy') + ->middleware(['auth:sanctum', 'verified']); + +Route::put('contacts/{contact}/restore', [ContactsController::class, 'restore']) + ->name('contacts.restore') + ->middleware(['auth:sanctum', 'verified']);