make documents polymorphic

shift-build-2464
Nadim Salloum 2021-06-25 17:35:37 +03:00
parent 9c747b2aee
commit a7cb0e9844
20 changed files with 172 additions and 61 deletions

View File

@ -373,6 +373,17 @@ class CarController extends Controller
'known_damage' => $car->known_damage, 'known_damage' => $car->known_damage,
'notes' => $car->notes, 'notes' => $car->notes,
'deleted_at' => $car->deleted_at, 'deleted_at' => $car->deleted_at,
'documents' => $car->documents()->orderBy('created_at', 'asc')->get()
->map(function ($document) {
return [
'id' => $document->id,
'name' => $document->name,
'size' => $document->size,
'extension' => $document->extension,
'link' => $document->link,
'created_at' => $document->created_at,
];
}),
'buy_contracts' => $car->buyContracts() 'buy_contracts' => $car->buyContracts()
->orderBy('date', 'desc') ->orderBy('date', 'desc')
->with('contact') ->with('contact')

View File

@ -212,6 +212,17 @@ class ContactController extends Controller
'city' => $contact->city, 'city' => $contact->city,
'country' => $contact->country, 'country' => $contact->country,
'deleted_at' => $contact->deleted_at, 'deleted_at' => $contact->deleted_at,
'documents' => $contact->documents()->orderBy('created_at', 'asc')->get()
->map(function ($document) {
return [
'id' => $document->id,
'name' => $document->name,
'size' => $document->size,
'extension' => $document->extension,
'link' => $document->link,
'created_at' => $document->created_at,
];
}),
'buy_contracts' => $contact->buyContracts() 'buy_contracts' => $contact->buyContracts()
->orderBy('date', 'desc') ->orderBy('date', 'desc')
->with('car') ->with('car')

View File

@ -7,10 +7,11 @@ use App\Models\Document;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\Redirect;
use Illuminate\Database\Eloquent\Relations\Relation;
class DocumentController extends Controller class DocumentController extends Controller
{ {
public function show(Contract $contract, Document $document) public function show(Document $document)
{ {
if (file_exists($document->path)) { if (file_exists($document->path)) {
header('Content-Disposition: filename="' . $document->name . '"'); header('Content-Disposition: filename="' . $document->name . '"');
@ -20,8 +21,14 @@ class DocumentController extends Controller
abort(404); abort(404);
} }
public function store(Request $request, Contract $contract) public function store(Request $request)
{ {
$class = $request->get('documentable_type');
$id = $request->get('documentable_id');
if (!in_array($class, ['contracts', 'cars', 'contacts'])) {
return [];
}
$file = $request->file()['document']; $file = $request->file()['document'];
$internalName = date('Y-m-d-H-i-s') . '.' . $file->extension(); $internalName = date('Y-m-d-H-i-s') . '.' . $file->extension();
$document = Document::create([ $document = Document::create([
@ -29,9 +36,10 @@ class DocumentController extends Controller
'internal_name' => $internalName, 'internal_name' => $internalName,
'size' => $file->getSize(), 'size' => $file->getSize(),
'extension' => $file->extension() ?? '', 'extension' => $file->extension() ?? '',
'contract_id' => $contract->id, 'documentable_type' => $class,
'documentable_id' => $id,
]); ]);
$file->move(public_path("documents/contracts/{$contract->id}/"), $internalName); $file->move(public_path("documents/{$class}/{$id}/"), $internalName);
return [ return [
'id' => $document->id, 'id' => $document->id,
@ -43,7 +51,7 @@ class DocumentController extends Controller
]; ];
} }
public function destroy(Request $request, Contract $contract) public function destroy(Request $request)
{ {
$document = Document::find((int)$request->get('id')); $document = Document::find((int)$request->get('id'));

View File

@ -2,9 +2,8 @@
namespace App\Models; namespace App\Models;
use App\Enums\ContractType;
use Carbon\Carbon; use Carbon\Carbon;
use Cknow\Money\Money; use App\Enums\ContractType;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
@ -25,6 +24,11 @@ class Car extends Model
'car_model_id', 'car_model_id',
]; ];
public function documents()
{
return $this->morphMany(Document::class, 'documentable');
}
public function getNameAttribute() public function getNameAttribute()
{ {
if (!$this->carModel) { if (!$this->carModel) {

View File

@ -25,6 +25,11 @@ class Contact extends Model
'notes', 'notes',
]; ];
public function documents()
{
return $this->morphMany(Document::class, 'documentable');
}
public function getNameAttribute() public function getNameAttribute()
{ {
return implode(' ', array_filter([$this->lastname, $this->firstname])); return implode(' ', array_filter([$this->lastname, $this->firstname]));

View File

@ -96,7 +96,7 @@ class Contract extends Model
public function documents() public function documents()
{ {
return $this->hasMany(Document::class); return $this->morphMany(Document::class, 'documentable');
} }
public function payments() public function payments()

View File

@ -15,9 +15,15 @@ class Document extends Model
'internal_name', 'internal_name',
'extension', 'extension',
'size', 'size',
'contract_id', 'documentable_type',
'documentable_id',
]; ];
public function documentable()
{
return $this->morphTo();
}
public function getCreatedAtAttribute($created_at) public function getCreatedAtAttribute($created_at)
{ {
return Carbon::parse($created_at)->format('d.m.Y'); return Carbon::parse($created_at)->format('d.m.Y');
@ -43,16 +49,11 @@ class Document extends Model
public function getLinkAttribute() public function getLinkAttribute()
{ {
return route('documents.show', [$this->contract->id, $this->id]); return route('documents.show', $this->id);
} }
public function getPathAttribute() public function getPathAttribute()
{ {
return public_path("documents/contracts/{$this->contract->id}/{$this->internal_name}"); return public_path("documents/{$this->documentable_type}/{$this->documentable->id}/{$this->internal_name}");
}
public function contract()
{
return $this->belongsTo(Contract::class)->withTrashed();
} }
} }

View File

@ -0,0 +1,32 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Relations\Relation;
class MorphServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
Relation::morphMap([
'contracts' => 'App\Models\Contract',
'cars' => 'App\Models\Car',
'contacts' => 'App\Models\Contact',
]);
}
/**
* Register services.
*
* @return void
*/
public function register()
{
//
}
}

View File

@ -41,15 +41,6 @@ class RouteServiceProvider extends ServiceProvider
$this->configureRateLimiting(); $this->configureRateLimiting();
$this->routes(function () { $this->routes(function () {
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
Route::bind('car', function ($value) { Route::bind('car', function ($value) {
if (in_array(Route::currentRouteName(), ['cars.show', 'cars.restore'])) { if (in_array(Route::currentRouteName(), ['cars.show', 'cars.restore'])) {
return Car::withTrashed()->find($value); return Car::withTrashed()->find($value);
@ -70,6 +61,15 @@ class RouteServiceProvider extends ServiceProvider
} }
return Contract::find($value); return Contract::find($value);
}); });
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}); });
} }

View File

@ -171,6 +171,7 @@ return [
*/ */
App\Providers\AppServiceProvider::class, App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class, App\Providers\AuthServiceProvider::class,
App\Providers\MorphServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class, // App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class, App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class, App\Providers\RouteServiceProvider::class,

View File

@ -26,7 +26,8 @@ class DocumentFactory extends Factory
return [ return [
'name' => 'Vertrag.pdf', 'name' => 'Vertrag.pdf',
'internal_name' => '2021-06-11-13:11:12.pdf', 'internal_name' => '2021-06-11-13:11:12.pdf',
'contract_id' => $this->faker->numberBetween(1, Contract::count()), 'documentable_id' => $this->faker->numberBetween(1, Contract::count()),
'documentable_type' => 'contracts',
'size' => $this->faker->numberBetween(1, 30000), 'size' => $this->faker->numberBetween(1, 30000),
'extension' => 'pdf', 'extension' => 'pdf',
]; ];

View File

@ -19,10 +19,7 @@ class CreateDocumentsTable extends Migration
$table->string('internal_name'); $table->string('internal_name');
$table->integer('size'); $table->integer('size');
$table->string('extension'); $table->string('extension');
$table->foreignId('contract_id') $table->morphs('documentable');
->onUpdate('cascade')
->onDelete('cascade')
->constrained('contracts');
$table->timestamps(); $table->timestamps();
}); });
} }

View File

@ -73,10 +73,6 @@ class DatabaseSeeder extends Seeder
$payments = Payment::factory() $payments = Payment::factory()
->count(60) ->count(60)
->create(); ->create();
$documents = Document::factory()
->count(40)
->create();
} }
public function getBrands(): array public function getBrands(): array

51
public/js/app.js vendored
View File

@ -18486,6 +18486,7 @@ var STATUS_FAILED = 2;
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
props: { props: {
id: Number, id: Number,
documentable_type: String,
documents: Object documents: Object
}, },
data: function data() { data: function data() {
@ -18517,7 +18518,8 @@ var STATUS_FAILED = 2;
// upload data to the server // upload data to the server
this.currentStatus = STATUS_SAVING; this.currentStatus = STATUS_SAVING;
axios.post(this.route('documents.store', this.id), formData).then(function (response) { console.log(this.route('documents.store'));
axios.post(this.route('documents.store'), formData).then(function (response) {
_this.documents.push(response.data); _this.documents.push(response.data);
_this.reset(); _this.reset();
@ -18529,7 +18531,9 @@ var STATUS_FAILED = 2;
filesChange: function filesChange(fieldName, fileList) { filesChange: function filesChange(fieldName, fileList) {
// handle file changes // handle file changes
var formData = new FormData(); var formData = new FormData();
if (!fileList.length) return; // append the files to FormData if (!fileList.length) return;
formData.append('documentable_type', this.documentable_type);
formData.append('documentable_id', this.id); // append the files to FormData
Array.from(Array(fileList.length).keys()).map(function (x) { Array.from(Array(fileList.length).keys()).map(function (x) {
formData.append(fieldName, fileList[x], fileList[x].name); formData.append(fieldName, fileList[x], fileList[x].name);
@ -18573,6 +18577,7 @@ __webpack_require__.r(__webpack_exports__);
props: { props: {
initial_documents: Object, initial_documents: Object,
id: Number, id: Number,
documentable_type: String,
show_upload: Boolean show_upload: Boolean
}, },
data: function data() { data: function data() {
@ -20737,6 +20742,8 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Components_Buttons_RestoreButton_vue__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @/Components/Buttons/RestoreButton.vue */ "./resources/js/Components/Buttons/RestoreButton.vue"); /* harmony import */ var _Components_Buttons_RestoreButton_vue__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @/Components/Buttons/RestoreButton.vue */ "./resources/js/Components/Buttons/RestoreButton.vue");
/* harmony import */ var _Components_Contracts_ContractTable_vue__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../Components/Contracts/ContractTable.vue */ "./resources/js/Components/Contracts/ContractTable.vue"); /* harmony import */ var _Components_Contracts_ContractTable_vue__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../Components/Contracts/ContractTable.vue */ "./resources/js/Components/Contracts/ContractTable.vue");
/* harmony import */ var _Components_SmallTitle_vue__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../Components/SmallTitle.vue */ "./resources/js/Components/SmallTitle.vue"); /* harmony import */ var _Components_SmallTitle_vue__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../Components/SmallTitle.vue */ "./resources/js/Components/SmallTitle.vue");
/* harmony import */ var _Components_Documents_View_vue__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @/Components/Documents/View.vue */ "./resources/js/Components/Documents/View.vue");
@ -20754,7 +20761,8 @@ __webpack_require__.r(__webpack_exports__);
DeleteButton: _Components_Buttons_DeleteButton_vue__WEBPACK_IMPORTED_MODULE_4__.default, DeleteButton: _Components_Buttons_DeleteButton_vue__WEBPACK_IMPORTED_MODULE_4__.default,
RestoreButton: _Components_Buttons_RestoreButton_vue__WEBPACK_IMPORTED_MODULE_5__.default, RestoreButton: _Components_Buttons_RestoreButton_vue__WEBPACK_IMPORTED_MODULE_5__.default,
ContractTable: _Components_Contracts_ContractTable_vue__WEBPACK_IMPORTED_MODULE_6__.default, ContractTable: _Components_Contracts_ContractTable_vue__WEBPACK_IMPORTED_MODULE_6__.default,
SmallTitle: _Components_SmallTitle_vue__WEBPACK_IMPORTED_MODULE_7__.default SmallTitle: _Components_SmallTitle_vue__WEBPACK_IMPORTED_MODULE_7__.default,
DocumentsView: _Components_Documents_View_vue__WEBPACK_IMPORTED_MODULE_8__.default
}, },
props: { props: {
car: Object car: Object
@ -21276,6 +21284,8 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Components_Buttons_RestoreButton_vue__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @/Components/Buttons/RestoreButton.vue */ "./resources/js/Components/Buttons/RestoreButton.vue"); /* harmony import */ var _Components_Buttons_RestoreButton_vue__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @/Components/Buttons/RestoreButton.vue */ "./resources/js/Components/Buttons/RestoreButton.vue");
/* harmony import */ var _Components_Contracts_ContractTable_vue__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../Components/Contracts/ContractTable.vue */ "./resources/js/Components/Contracts/ContractTable.vue"); /* harmony import */ var _Components_Contracts_ContractTable_vue__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../Components/Contracts/ContractTable.vue */ "./resources/js/Components/Contracts/ContractTable.vue");
/* harmony import */ var _Components_SmallTitle_vue__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../Components/SmallTitle.vue */ "./resources/js/Components/SmallTitle.vue"); /* harmony import */ var _Components_SmallTitle_vue__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../Components/SmallTitle.vue */ "./resources/js/Components/SmallTitle.vue");
/* harmony import */ var _Components_Documents_View_vue__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @/Components/Documents/View.vue */ "./resources/js/Components/Documents/View.vue");
@ -21293,7 +21303,8 @@ __webpack_require__.r(__webpack_exports__);
DeleteButton: _Components_Buttons_DeleteButton_vue__WEBPACK_IMPORTED_MODULE_4__.default, DeleteButton: _Components_Buttons_DeleteButton_vue__WEBPACK_IMPORTED_MODULE_4__.default,
RestoreButton: _Components_Buttons_RestoreButton_vue__WEBPACK_IMPORTED_MODULE_5__.default, RestoreButton: _Components_Buttons_RestoreButton_vue__WEBPACK_IMPORTED_MODULE_5__.default,
ContractTable: _Components_Contracts_ContractTable_vue__WEBPACK_IMPORTED_MODULE_6__.default, ContractTable: _Components_Contracts_ContractTable_vue__WEBPACK_IMPORTED_MODULE_6__.default,
SmallTitle: _Components_SmallTitle_vue__WEBPACK_IMPORTED_MODULE_7__.default SmallTitle: _Components_SmallTitle_vue__WEBPACK_IMPORTED_MODULE_7__.default,
DocumentsView: _Components_Documents_View_vue__WEBPACK_IMPORTED_MODULE_8__.default
}, },
props: { props: {
contact: Object contact: Object
@ -23546,7 +23557,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
var _component_document_upload = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("document-upload"); var _component_document_upload = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("document-upload");
return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_small_title, { return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)("div", null, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_small_title, {
title: "Dokumente", title: "Dokumente",
"class": "mb-3" "class": "mb-3"
}), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("div", _hoisted_1, [((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($data.documents, function (document) { }), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("div", _hoisted_1, [((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($data.documents, function (document) {
@ -23562,12 +23573,11 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
)), $props.show_upload ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(_component_document_upload, { )), $props.show_upload ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(_component_document_upload, {
key: 0, key: 0,
id: $props.id, id: $props.id,
documentable_type: $props.documentable_type,
documents: $data.documents documents: $data.documents
}, null, 8 }, null, 8
/* PROPS */ /* PROPS */
, ["id", "documents"])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true)])], 64 , ["id", "documentable_type", "documents"])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true)])]);
/* STABLE_FRAGMENT */
);
} }
/***/ }), /***/ }),
@ -28417,6 +28427,8 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
var _component_contract_table = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("contract-table"); var _component_contract_table = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("contract-table");
var _component_documents_view = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("documents-view");
var _component_show_page = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("show-page"); var _component_show_page = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("show-page");
return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(_component_show_page, null, { return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(_component_show_page, null, {
@ -28478,7 +28490,15 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
title: $props.car.sell_contracts.length > 1 ? $props.car.sell_contracts.length + ' Verkaufsverträge' : 'Verkaufsvertrag' title: $props.car.sell_contracts.length > 1 ? $props.car.sell_contracts.length + ' Verkaufsverträge' : 'Verkaufsvertrag'
}, null, 8 }, null, 8
/* PROPS */ /* PROPS */
, ["contracts", "carId", "show_upload", "title"])]; , ["contracts", "carId", "show_upload", "title"]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_documents_view, {
"class": "mt-5",
initial_documents: $props.car.documents,
id: $props.car.id,
documentable_type: "cars",
show_upload: !$props.car.deleted_at
}, null, 8
/* PROPS */
, ["initial_documents", "id", "show_upload"])];
}), }),
_: 1 _: 1
/* STABLE */ /* STABLE */
@ -29307,6 +29327,8 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
var _component_contract_table = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("contract-table"); var _component_contract_table = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("contract-table");
var _component_documents_view = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("documents-view");
var _component_show_page = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("show-page"); var _component_show_page = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("show-page");
return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(_component_show_page, null, { return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(_component_show_page, null, {
@ -29368,7 +29390,15 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
title: $props.contact.sell_contracts.length > 1 ? $props.contact.sell_contracts.length + ' Verkaufsverträge' : 'Verkaufsvertrag' title: $props.contact.sell_contracts.length > 1 ? $props.contact.sell_contracts.length + ' Verkaufsverträge' : 'Verkaufsvertrag'
}, null, 8 }, null, 8
/* PROPS */ /* PROPS */
, ["contracts", "contactId", "show_upload", "title"])]; , ["contracts", "contactId", "show_upload", "title"]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_documents_view, {
"class": "mt-5",
initial_documents: $props.contact.documents,
id: $props.contact.id,
documentable_type: "contacts",
show_upload: !$props.contact.deleted_at
}, null, 8
/* PROPS */
, ["initial_documents", "id", "show_upload"])];
}), }),
_: 1 _: 1
/* STABLE */ /* STABLE */
@ -30069,6 +30099,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
, ["payments", "contract"]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_documents_view, { , ["payments", "contract"]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_documents_view, {
initial_documents: $props.contract.documents, initial_documents: $props.contract.documents,
id: $props.contract.id, id: $props.contract.id,
documentable_type: "contracts",
show_upload: !$props.contract.deleted_at show_upload: !$props.contract.deleted_at
}, null, 8 }, null, 8
/* PROPS */ /* PROPS */

View File

@ -24,6 +24,7 @@ const STATUS_INITIAL = 0; const STATUS_SAVING = 1; const
export default { export default {
props: { props: {
id: Number, id: Number,
documentable_type: String,
documents: Object, documents: Object,
}, },
data() { data() {
@ -53,7 +54,8 @@ export default {
save(formData) { save(formData) {
// upload data to the server // upload data to the server
this.currentStatus = STATUS_SAVING; this.currentStatus = STATUS_SAVING;
axios.post(this.route('documents.store', this.id), formData) console.log(this.route('documents.store'));
axios.post(this.route('documents.store'), formData)
.then((response) => { .then((response) => {
this.documents.push(response.data); this.documents.push(response.data);
this.reset(); this.reset();
@ -69,6 +71,9 @@ export default {
if (!fileList.length) return; if (!fileList.length) return;
formData.append('documentable_type', this.documentable_type);
formData.append('documentable_id', this.id);
// append the files to FormData // append the files to FormData
Array Array
.from(Array(fileList.length).keys()) .from(Array(fileList.length).keys())

View File

@ -1,11 +1,13 @@
<template> <template>
<small-title title="Dokumente" class="mb-3" /> <div>
<div class="grid md:grid-cols-6 sm:grid-cols-4 grid-cols-2 gap-3"> <small-title title="Dokumente" class="mb-3" />
<template v-for="document in documents" :key="document.id"> <div class="grid md:grid-cols-6 sm:grid-cols-4 grid-cols-2 gap-3">
<document-item @delete="deleteDocument" :document="document" /> <template v-for="document in documents" :key="document.id">
</template> <document-item @delete="deleteDocument" :document="document" />
<document-upload v-if="show_upload" :id="id" :documents="documents" /> </template>
</div> <document-upload v-if="show_upload" :id="id" :documentable_type="documentable_type" :documents="documents" />
</div>
</div>
</template> </template>
<script> <script>
@ -23,6 +25,7 @@ export default {
props: { props: {
initial_documents: Object, initial_documents: Object,
id: Number, id: Number,
documentable_type: String,
show_upload: Boolean, show_upload: Boolean,
}, },
data() { data() {

View File

@ -34,6 +34,7 @@
:show_upload="!car.deleted_at" :show_upload="!car.deleted_at"
:title="car.sell_contracts.length > 1 ? car.sell_contracts.length + ' Verkaufsverträge' : 'Verkaufsvertrag'" :title="car.sell_contracts.length > 1 ? car.sell_contracts.length + ' Verkaufsverträge' : 'Verkaufsvertrag'"
/> />
<documents-view class="mt-5" :initial_documents="car.documents" :id="car.id" documentable_type="cars" :show_upload="!car.deleted_at" />
</template> </template>
</show-page> </show-page>
</template> </template>
@ -47,6 +48,7 @@ import DeleteButton from '@/Components/Buttons/DeleteButton.vue';
import RestoreButton from '@/Components/Buttons/RestoreButton.vue'; import RestoreButton from '@/Components/Buttons/RestoreButton.vue';
import ContractTable from '../../Components/Contracts/ContractTable.vue'; import ContractTable from '../../Components/Contracts/ContractTable.vue';
import SmallTitle from '../../Components/SmallTitle.vue'; import SmallTitle from '../../Components/SmallTitle.vue';
import DocumentsView from '@/Components/Documents/View.vue';
export default { export default {
components: { components: {
@ -58,6 +60,7 @@ export default {
RestoreButton, RestoreButton,
ContractTable, ContractTable,
SmallTitle, SmallTitle,
DocumentsView,
}, },
props: { props: {
car: Object, car: Object,

View File

@ -37,6 +37,7 @@
:show_upload="!contact.deleted_at" :show_upload="!contact.deleted_at"
:title="contact.sell_contracts.length > 1 ? contact.sell_contracts.length + ' Verkaufsverträge' : 'Verkaufsvertrag'" :title="contact.sell_contracts.length > 1 ? contact.sell_contracts.length + ' Verkaufsverträge' : 'Verkaufsvertrag'"
/> />
<documents-view class="mt-5" :initial_documents="contact.documents" :id="contact.id" documentable_type="contacts" :show_upload="!contact.deleted_at" />
</template> </template>
</show-page> </show-page>
</template> </template>
@ -50,6 +51,7 @@ import DeleteButton from '@/Components/Buttons/DeleteButton.vue';
import RestoreButton from '@/Components/Buttons/RestoreButton.vue'; import RestoreButton from '@/Components/Buttons/RestoreButton.vue';
import ContractTable from '../../Components/Contracts/ContractTable.vue'; import ContractTable from '../../Components/Contracts/ContractTable.vue';
import SmallTitle from '../../Components/SmallTitle.vue'; import SmallTitle from '../../Components/SmallTitle.vue';
import DocumentsView from '@/Components/Documents/View.vue';
export default { export default {
components: { components: {
@ -61,6 +63,7 @@ export default {
RestoreButton, RestoreButton,
ContractTable, ContractTable,
SmallTitle, SmallTitle,
DocumentsView,
}, },
props: { props: {

View File

@ -81,7 +81,7 @@
<payments-upload v-if="!contract.deleted_at" :show_upload="!contract.deleted_at" :contract="contract" /> <payments-upload v-if="!contract.deleted_at" :show_upload="!contract.deleted_at" :contract="contract" />
</span> </span>
<payments-view :payments="contract.payments" :contract="contract" /> <payments-view :payments="contract.payments" :contract="contract" />
<documents-view :initial_documents="contract.documents" :id="contract.id" :show_upload="!contract.deleted_at" /> <documents-view :initial_documents="contract.documents" :id="contract.id" documentable_type="contracts" :show_upload="!contract.deleted_at" />
</template> </template>
</show-page> </show-page>
</template> </template>

View File

@ -9,7 +9,6 @@ use App\Http\Controllers\PaymentController;
use App\Http\Controllers\ContractController; use App\Http\Controllers\ContractController;
use App\Http\Controllers\DocumentController; use App\Http\Controllers\DocumentController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
Route::middleware(['auth:sanctum', 'verified'])->group(function () { Route::middleware(['auth:sanctum', 'verified'])->group(function () {
Route::get('/', [ContractController::class, 'dashboard'])->name('dashboard'); Route::get('/', [ContractController::class, 'dashboard'])->name('dashboard');
@ -75,13 +74,13 @@ Route::middleware(['auth:sanctum', 'verified'])->group(function () {
Route::post('/', [PaymentController::class, 'store'])->name('payments.store'); Route::post('/', [PaymentController::class, 'store'])->name('payments.store');
}); });
Route::prefix('documents')->group(function () {
Route::get('{document}', [DocumentController::class, 'show'])->name('documents.show');
Route::delete('delete', [DocumentController::class, 'destroy'])->name('documents.destroy');
Route::post('/', [DocumentController::class, 'store'])->name('documents.store');
});
}); });
});
Route::prefix('documents')->group(function () {
Route::get('{document}', [DocumentController::class, 'show'])->name('documents.show');
Route::delete('delete', [DocumentController::class, 'destroy'])->name('documents.destroy');
Route::post('upload', [DocumentController::class, 'store'])->name('documents.store');
}); });
Route::post('brands', [BrandController::class, 'store'])->name('brands.store'); Route::post('brands', [BrandController::class, 'store'])->name('brands.store');