raffles document uploader added / Free Resource Completed

This commit is contained in:
2025-08-03 00:01:49 +05:45
parent efa9231391
commit a3b863970e
25 changed files with 472 additions and 1062 deletions

View File

@@ -4,48 +4,37 @@ APP_KEY=
APP_DEBUG=true APP_DEBUG=true
APP_TIMEZONE=UTC APP_TIMEZONE=UTC
APP_URL=http://localhost APP_URL=http://localhost
APP_LOCALE=en APP_LOCALE=en
APP_FALLBACK_LOCALE=en APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database # APP_MAINTENANCE_STORE=database
BCRYPT_ROUNDS=12 BCRYPT_ROUNDS=12
LOG_CHANNEL=stack LOG_CHANNEL=stack
LOG_STACK=single LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_CONNECTION=sqlite DB_HOST=127.0.0.1
# DB_HOST=127.0.0.1 DB_PORT=3306
# DB_PORT=3306 DB_DATABASE=raffles
# DB_DATABASE=laravel DB_USERNAME=root
# DB_USERNAME=root DB_PASSWORD=
# DB_PASSWORD=
SESSION_DRIVER=database SESSION_DRIVER=database
SESSION_LIFETIME=120 SESSION_LIFETIME=120
SESSION_ENCRYPT=false SESSION_ENCRYPT=false
SESSION_PATH=/ SESSION_PATH=/
SESSION_DOMAIN=null SESSION_DOMAIN=null
BROADCAST_CONNECTION=log BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local FILESYSTEM_DISK=local
QUEUE_CONNECTION=database QUEUE_CONNECTION=database
CACHE_STORE=database CACHE_STORE=database
CACHE_PREFIX= CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1 MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1 REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null REDIS_PASSWORD=null
REDIS_PORT=6379 REDIS_PORT=6379
MAIL_MAILER=log MAIL_MAILER=log
MAIL_HOST=127.0.0.1 MAIL_HOST=127.0.0.1
MAIL_PORT=2525 MAIL_PORT=2525
@@ -54,11 +43,9 @@ MAIL_PASSWORD=null
MAIL_ENCRYPTION=null MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com" MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}" MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID= AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY= AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1 AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET= AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}" VITE_APP_NAME="${APP_NAME}"

View File

@@ -8,10 +8,12 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Modules\CCMS\Traits\UpdateCustomFields; use Modules\CCMS\Traits\UpdateCustomFields;
use Modules\Document\Models\Document; use Modules\Document\Models\Document;
use App\Traits\AddToDocumentCollection;
class Country extends Model class Country extends Model
{ {
use HasFactory, UpdateCustomFields, CreatedUpdatedBy; use HasFactory, AddToDocumentCollection, UpdateCustomFields, CreatedUpdatedBy;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.
@@ -102,4 +104,5 @@ class Country extends Model
{ {
return $this->morphMany(Document::class, 'documentable'); return $this->morphMany(Document::class, 'documentable');
} }
} }

View File

@@ -8,10 +8,12 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Modules\CCMS\Traits\UpdateCustomFields; use Modules\CCMS\Traits\UpdateCustomFields;
use Modules\Document\Models\Document; use Modules\Document\Models\Document;
use App\Traits\AddToDocumentCollection;
class Service extends Model class Service extends Model
{ {
use HasFactory, UpdateCustomFields, CreatedUpdatedBy; use HasFactory, UpdateCustomFields, AddToDocumentCollection, CreatedUpdatedBy;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.

View File

@@ -8,12 +8,13 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Modules\CCMS\Traits\UpdateCustomFields; use Modules\CCMS\Traits\UpdateCustomFields;
use Modules\Document\Models\Document; use Modules\Document\Models\Document;
use App\Traits\AddToDocumentCollection;
// use Modules\CCMS\Database\Factories\TestFactory; // use Modules\CCMS\Database\Factories\TestFactory;
class Test extends Model class Test extends Model
{ {
use HasFactory, UpdateCustomFields, CreatedUpdatedBy; use HasFactory, UpdateCustomFields, AddToDocumentCollection, CreatedUpdatedBy;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.

View File

@@ -6,10 +6,13 @@ use App\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Modules\CCMS\Models\Country; use Modules\CCMS\Models\Country;
use Modules\Document\Models\Document;
use Modules\CCMS\Models\Service; use Modules\CCMS\Models\Service;
use Modules\CCMS\Models\Test; use Modules\CCMS\Models\Test;
use Modules\Document\Services\DocumentService; use Modules\Document\Services\DocumentService;
use Yajra\DataTables\Facades\DataTables; use Yajra\DataTables\Facades\DataTables;
use Illuminate\Support\Facades\Validator;
class DocumentController extends Controller class DocumentController extends Controller
{ {
@@ -33,39 +36,151 @@ class DocumentController extends Controller
} }
public function dropzoneUpload(Request $request) public function destroy($id)
{ {
$request->validate([ try {
'model' => 'required|string', $document = Document::findOrFail($id);
'file' => 'required|array', if (File::exists('storage/' . $document->document_path)) {
'file.*' => 'file|mimes:pdf,doc,docx,jpg,png|max:5120', File::delete('storage/' . $document->document_path);
'title' => 'nullable|string', }
$document->delete();
session()->flash('Document Deleted');
return response()->json(['status' => true, 'msg' => 'Document Deleted']);
} catch (\Throwable $th) {
session()->flash('error', $th->getMessage());
}
}
public function uploadDocument(Request $request)
{
$isNumeric = is_numeric($request->title);
$validator = Validator::make($request->all(), [
'title' => $isNumeric ? 'required|exists:required_documents,id' : 'required|string',
'model' => 'required',
'document' => 'required|array',
], [
'title.required' => 'Document title is required!',
'title.exists' => 'Document does not exists in record!',
'document' => 'Please upload document first!',
'model' => 'Please Select Category'
]); ]);
$parts = explode(':', $request->model); if ($validator->fails()) {
return response()->json(['status' => 422, 'errors' => $validator->errors()], 422);
if (count($parts) !== 2) {
return response()->json(['error' => 'Invalid model format.'], 422);
} }
[$modelType, $modelId] = $parts; try {
$modelClass = "App\\Models\\$modelType";
if (!class_exists($modelClass)) { $modelValues = explode(':', $request->model);
return response()->json(['error' => 'Invalid model selected.'], 422); $modelClass = "Modules\\CCMS\\Models\\{$modelValues[0]}";
$model = $modelClass::findOrFail($modelValues[1]);
foreach ($request->input('document', []) as $file) {
$model->addToDocumentCollection(collectionName: 'uploads/document', file: $file, documentName: $request->title, referenceDocumentId: null);
} }
$model = $modelClass::findOrFail($modelId); return response()->json([
'status' => true,
'msg' => 'Document has been uploaded!',
// 'view' => view('student::student.section.document.table', [
// 'student' => $student,
// ])->render(),
], 200);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'msg' => $th->getMessage(),
], 500);
}
}
foreach ($request->file('file') as $uploadedFile) { public function store(Request $request)
$path = $uploadedFile->store('documents'); {
$path = storage_path('tmp/uploads');
$model->documents()->create([ if (!file_exists($path)) {
'title' => $request->title ?? 'Untitled', mkdir($path, 0777, true);
'file_path' => $path, }
$file = $request->file('file');
$name = uniqid() . '_' . trim($file->getClientOriginalName());
$file->move($path, $name);
return response()->json([
'name' => $name,
'original_name' => $file->getClientOriginalName(),
]); ]);
} }
return response()->json(['success' => 'Files uploaded successfully']); public function getAllDocuments()
{
$model = Document::query()->latest();
return DataTables::eloquent($model)
->setRowClass('tableRow')
->addColumn('name', function (Document $document) {
$extension = $document->getExtension();
$assetUrl = $document->getUrl();
$html = $document->isImageFile()
? "<div class='flex-shrink-0'>
<div class='avatar-sm bg-light rounded p-1'>
<a href='{$assetUrl}' data-fancybox='gallery' data-caption='{$document->title}'>
<img src='{$assetUrl}' alt='' class='avatar-sm img-fluid d-block'>
</a>
</div>
</div>"
: "<div class='flex-shrink-0'>
<div class='avatar-sm'>
<a href='{$assetUrl}' data-fancybox='gallery' data-caption='{$document->title}'>
<div class='avatar-title bg-" . getFileIcon($extension)[1] . "-subtle text-" . getFileIcon($extension)[1] . " fs-20 material-shadow rounded'>
<i class='" . getFileIcon($extension)[0] . "'></i>
</div>
</a>
</div>
</div>";
return "<div class='d-flex align-items-center'>
{$html} <div class='flex-grow-1 ms-3'>
<h6 class='fs-12 mb-0'>{$document->title}</h6>
</div>
</div>";
})
->addColumn('type', function (Document $document) {
return $document->getExtension();
})
->addColumn('size', function (Document $document) {
return $document->getSize();
})
->editColumn('created_at', function (Document $document) {
return getFormatted($document->created_at);
})
->addColumn('action', function (Document $document) {
return view('document::document.partials.action', ['document' => $document]);
})
->rawColumns(['action', 'name', 'size'])
->toJson();
}
public function reorder(Request $request)
{
Document::chunkById(100, function (Collection $documents) use ($request) {
foreach ($documents as $document) {
foreach ($request->order as $order) {
if ($order['id'] == $document->id) {
$document->update(['order' => $order['position']]);
}
}
}
});
return response(['status' => true, 'message' => 'Reordered successfully'], 200);
} }
} }

View File

@@ -13,9 +13,16 @@ class Document extends Model
{ {
use HasFactory; use HasFactory;
protected $fillable = ['title', 'file_path']; protected $fillable = ['title', 'file_path', 'collection_name', 'order'];
protected static function booted()
{
static::creating(function ($model) {
$model->order = ($model::max('order') ?? 0) + 1;
});
}
public function documentable(): MorphTo public function documentable(): MorphTo
{ {
return $this->morphTo(); return $this->morphTo();
@@ -23,13 +30,13 @@ class Document extends Model
public function getUrl() public function getUrl()
{ {
$path = $this->document_path; $path = $this->collection_name . '/' . $this->file_path;
return Storage::disk('public')->url($path); return Storage::disk('public')->url($path);
} }
public function getSize() public function getSize()
{ {
$path = $this->document_path; $path = $this->collection_name . '/' . $this->file_path;
if (Storage::disk('public')->exists($path)) { if (Storage::disk('public')->exists($path)) {
$sizeInBytes = Storage::disk('public')->size($path); $sizeInBytes = Storage::disk('public')->size($path);
@@ -41,13 +48,13 @@ class Document extends Model
public function getExtension() public function getExtension()
{ {
return pathinfo($this->document_path, PATHINFO_EXTENSION); return pathinfo($this->file_path, PATHINFO_EXTENSION);
} }
public function isImageFile() public function isImageFile()
{ {
$imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp', 'tiff', 'tif', 'ico']; $imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp', 'tiff', 'tif', 'ico'];
$extension = pathinfo($this->document_path, PATHINFO_EXTENSION); $extension = pathinfo($this->file_path, PATHINFO_EXTENSION);
return in_array(Str::lower($extension), $imageExtensions); return in_array(Str::lower($extension), $imageExtensions);
} }
@@ -56,7 +63,7 @@ class Document extends Model
return Attribute::make( return Attribute::make(
get: function (mixed $value, array $attributes) { get: function (mixed $value, array $attributes) {
$collectionName = $attributes['collection_name']; $collectionName = $attributes['collection_name'];
$path = $attributes['document_path']; $path = $attributes['file_path'];
return "{$collectionName}/{$path}"; return "{$collectionName}/{$path}";
} }
); );

View File

@@ -13,11 +13,12 @@ return new class extends Migration
{ {
Schema::create('documents', function (Blueprint $table) { Schema::create('documents', function (Blueprint $table) {
$table->id(); $table->id();
$table->string('title'); $table->string('title')->nullable();
$table->string('file_path'); $table->string('file_path')->nullable();
$table->string('collection_name')->default('uploads');
$table->unsignedBigInteger('documentable_id'); $table->unsignedBigInteger('documentable_id');
$table->string('documentable_type'); $table->string('documentable_type');
$table->index(['documentable_type', 'documentable_id']); $table->unsignedBigInteger("order")->nullable();
$table->timestamps(); $table->timestamps();
}); });
} }

View File

@@ -2,9 +2,7 @@
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
<form method="POST" action="{{ route('documents.dropzone.upload') }}" class="dropzone" id="mainForm" {{ html()->form('POST', route('documents.upload'))->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data', 'id' => 'documentForm'])->open() }}
enctype="multipart/form-data">
@csrf
<div class="mb-3"> <div class="mb-3">
{{ html()->label('Title')->for('title') }} {{ html()->label('Title')->for('title') }}
@@ -15,74 +13,102 @@
<div class="mb-3"> <div class="mb-3">
{{ html()->label('Select Model')->class('form-label')->for('model') }} {{ html()->label('Select Model')->class('form-label')->for('model') }}
{{ html()->span('*')->class('text-danger') }} {{ html()->span('*')->class('text-danger') }}
{{ html()->select('model')->id('modelSelect')->class('form-select')->required()->options(['' => '-- Select --'] + $modelOptions->toArray()) }} {{ html()->select('model')->id('modelSelect')->class('form-select select2')->required()->options(['' => '-- Select --'] + $modelOptions->toArray()) }}
</div> </div>
<div class="dropzone-previews mb-3"></div> <div class="mb-3">
<x-document::file-upload :uploadUrl="route('documents.store')" dropzoneId="document-dropzone"
<div class="dz-message mb-3"> formId="documentForm" message="Upload Document (PDF or Images Only)"
<p class="fs-14">Drop files here or click to upload.</p> inputName="document" />
</div> </div>
<button type="button" class="btn btn-primary" id="submitAll">Submit</button> <div class="col-sm-12">
</form> <div class="hstack justify-content-end gap-2">
<button type="submit" class="btn btn-primary upload-btn">Upload</button>
</div>
</div>
{{ html()->form()->close() }}
</div> </div>
</div> </div>
</div> </div>
@push('js')
<script>
document.addEventListener("DOMContentLoaded", function() {
Dropzone.autoDiscover = false;
const myDropzone = new Dropzone("#mainForm", { @pushOnce('js')
url: "{{ route('documents.dropzone.upload') }}", <script>
autoProcessQueue: false, function clearDropzone(dropzoneIds = [], formId = '', fileFieldNames = []) {
uploadMultiple: true, dropzoneIds.forEach(function(id) {
parallelUploads: 5, const dropzoneElement = Dropzone.forElement(`#${id}`);
maxFilesize: 5, if (dropzoneElement) {
addRemoveLinks: true, dropzoneElement.removeAllFiles(true);
acceptedFiles: ".pdf,.doc,.docx,.jpg,.png", }
paramName: "file[]", });
fileFieldNames.forEach(function(field) {
$(`#${formId} input[name="${field}[]"]`).remove();
});
}
</script>
<script>
$(document).on('submit', '#documentForm', function(event) {
event.preventDefault();
const url = $(this).attr('action');
const formData = new FormData(this);
const button = $(this).find('button[type="submit"]');
$.ajax({
type: "POST",
url: url,
data: formData,
processData: false,
contentType: false,
headers: { headers: {
'X-CSRF-TOKEN': document.querySelector('input[name="_token"]').value 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
}, },
init: function() { beforeSend: () => {
const dz = this; button.text('Uploading...').prop('disabled', true);
},
success: (response) => {
if (response.status == true) {
$('#documentForm')[0].reset();
document.getElementById("submitAll").addEventListener("click", function(e) { // if (DataTable.isDataTable("#documents-table")) {
const title = document.getElementById('docTitle').value; // $("#documents-table").DataTable().ajax.reload();
const model = document.getElementById('modelSelect').value; // } else {
// target.html(response.view);
// }
clearDropzone(dropzoneIds = ["document-dropzone"],
"documentForm", ["document"]);
button.text('Upload').prop('disabled', false);
toastr.success(response.msg);
if (!title || !model) {
alert("Please fill in both Title and Model.");
return;
} }
},
error: (xhr) => {
if (xhr.status === 422) {
const errors = xhr.responseJSON.errors;
$('.error-message').remove();
if (dz.getQueuedFiles().length > 0) { for (const [key, value] of Object.entries(errors)) {
dz.processQueue(); const errorMessage = $(
'<p class="error-message text-danger mt-2"></p>').text(
value[0]);
$(`#${key}`).after(errorMessage);
}
} else { } else {
alert("Please select at least one file."); console.error(xhr);
} }
}); },
complete: () => {
dz.on("sending", function(file, xhr, formData) { button.text('Upload');
formData.append("title", document.getElementById('docTitle').value); button.prop('disabled', true);
formData.append("model", document.getElementById('modelSelect').value);
});
dz.on("successmultiple", function(files, response) {
alert("Files uploaded successfully.");
dz.removeAllFiles();
document.getElementById('mainForm').reset();
});
dz.on("errormultiple", function(files, response) {
alert("An error occurred during upload.");
console.error(response);
});
} }
}); });
}); });
</script> </script>
@endpush @endPushOnce

View File

@@ -8,26 +8,17 @@
@endif @endif
<div class="row"> <div class="row">
<div class="col-lg-6 col-xl-6"> <div class="col-lg-4 col-xl-4">
<div class="card profile-card"> <div class="card profile-card">
@include('document::document.form') @include('document::document.form')
</div> </div>
</div> </div>
{{-- <div class="col-lg-xl-8 col-lg-9"> <div class="col-lg-xl-8 col-lg-8">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
@php @php
$columns = [ $columns = [
[
'title' => '<input type="checkbox" id="select-all">',
'data' => 'checkbox',
'name' => 'checkbox',
'orderable' => false,
'searchable' => false,
'printable' => false,
'exportable' => false,
],
['title' => 'Document', 'data' => 'name', 'name' => 'name'], ['title' => 'Document', 'data' => 'name', 'name' => 'name'],
['title' => 'Type', 'data' => 'type', 'name' => 'type'], ['title' => 'Type', 'data' => 'type', 'name' => 'type'],
['title' => 'Size', 'data' => 'size', 'name' => 'size'], ['title' => 'Size', 'data' => 'size', 'name' => 'size'],
@@ -41,10 +32,11 @@
]; ];
@endphp @endphp
<x-data-table-script :route="route('gallery.index')" :reorder="route('gallery.reorder')" :columns="$columns" /> <x-data-table-script :route="route('documents.getAllDocuments')" :columns="$columns" id="documents-table" :reorder="route('documents.reorder')" />
</div>
</div> </div>
</div> </div>
</div> --}}
</div> </div>
</div> </div>
@endsection @endsection

View File

@@ -0,0 +1,7 @@
<div class="hstack flex-wrap gap-3 align-items-center">
<a href="{{ $document->getUrl() }}" class="link-primary fs-15" download><i class="ri-download-2-line"></i></a>
@can('documents.destroy')
<a href="javascript:void(0);" data-link="{{ route('documents.destroy', $document->id) }}"
class="link-danger fs-15 remove-item"><i class="ri-delete-bin-line"></i></a>
@endcan
</div>

View File

@@ -15,6 +15,9 @@ use Modules\Document\Http\Controllers\DocumentController;
*/ */
Route::group(['middleware' => ['web', 'auth', 'permission'], 'prefix' => 'admin/'], function () { Route::group(['middleware' => ['web', 'auth', 'permission'], 'prefix' => 'admin/'], function () {
Route::get('/documents', [DocumentController::class, 'index'])->name('documents.index'); // Route::get('/documents', [DocumentController::class, 'index'])->name('documents.index');
Route::post('/documents/dropzone-upload', [DocumentController::class, 'dropzoneUpload'])->name('documents.dropzone.upload'); Route::post('documents/reorder', [DocumentController::class, 'reorder'])->name('documents.reorder');
Route::resource('documents', DocumentController::class)->names('documents');
Route::post('/documents/upload', [DocumentController::class, 'uploadDocument'])->name('documents.upload');
Route::get('get-all-documents', [DocumentController::class, 'getAllDocuments'])->name('documents.getAllDocuments');
}); });

View File

@@ -20,6 +20,49 @@ if (!function_exists('setting')) {
} }
} }
if (!function_exists('getFileIcon')) {
function getFileIcon($extension)
{
switch ($extension) {
case 'pdf':
return ['ri-file-pdf-line', 'danger'];
case 'doc':
case 'docx':
return ['ri-file-word-line', 'primary'];
case 'xls':
case 'xlsx':
return ['ri-file-excel-line', 'success'];
case 'ppt':
case 'pptx':
return ['ri-file-powerpoint-line', 'danger'];
case 'txt':
return ['ri-file-alt-line', 'secondary'];
case 'jpg':
case 'jpeg':
case 'png':
case 'gif':
return ['ri-file-image-line', 'info'];
case 'zip':
case 'rar':
return ['ri-file-archive-line', 'warning'];
case 'mp3':
case 'wav':
return ['ri-file-audio-line', 'warning'];
case 'mp4':
case 'mov':
case 'avi':
return ['ri-file-video-line', 'warning'];
default:
return ['ri-file-line', 'warning'];
}
// return collect([
// 'icon' => $res[0],
// 'color' => $res[1],
// ]);
}
}
if (!function_exists('uploadImage')) { if (!function_exists('uploadImage')) {
function uploadImage($file, $path = 'uploads') function uploadImage($file, $path = 'uploads')
{ {

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Modules\Document\Models\Document;
trait AddToDocumentCollection
{
public function addToDocumentCollection(string $collectionName = 'uploads', string $file, ?string $documentName = null, ?int $referenceDocumentId = null)
{
if (!Storage::disk('public')->exists($collectionName)) {
Storage::disk('public')->makeDirectory($collectionName);
}
$targetFile = Storage::disk('public')->path("{$collectionName}/{$file}");
File::copy(storage_path("tmp/uploads/{$file}"), $targetFile);
$this->documents()->create([
'title' => $documentName,
'file_path' => $file,
'collection_name' => $collectionName,
]);
}
public function documents(): MorphMany
{
return $this->morphMany(Document::class, 'documentable')->orderBy('order');
}
}

View File

@@ -228,10 +228,10 @@ return [
[ [
'text' => 'Documents', 'text' => 'Documents',
'url' => 'admin/document', 'url' => 'admin/documents',
'icon' => 'ri-file-text-line', 'icon' => 'ri-file-text-line',
'module' => 'Document', 'module' => 'Document',
'can' => ['document.index'], 'can' => ['documents.index'],
], ],
[ [
'text' => 'Resume Builder', 'text' => 'Resume Builder',

View File

@@ -31,7 +31,7 @@
<link href="{{ asset('assets/css/custom.min.css') }}" rel="stylesheet" type="text/css" /> <link href="{{ asset('assets/css/custom.min.css') }}" rel="stylesheet" type="text/css" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.css" rel="stylesheet"> <link href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.css" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.css" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" rel="stylesheet" />
@livewireStyles @livewireStyles
@stack('css') @stack('css')
@@ -119,6 +119,7 @@
<script> <script>
const app_url = "{{ config('app.url') }}"; const app_url = "{{ config('app.url') }}";
</script> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js"></script>
<script src="{{ asset('assets/libs/jquery/jquery-3.7.1.min.js') }}"></script> <script src="{{ asset('assets/libs/jquery/jquery-3.7.1.min.js') }}"></script>
<script src="{{ asset('assets/libs/bootstrap/js/bootstrap.bundle.min.js') }}"></script> <script src="{{ asset('assets/libs/bootstrap/js/bootstrap.bundle.min.js') }}"></script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.