Updated: Product Image Uploading (Added Multiple Image Upload)

This commit is contained in:
Fahim 2021-08-11 23:37:11 +06:00
parent c381a0dc40
commit c197ade809
48 changed files with 4670 additions and 72093 deletions

View File

@ -21,7 +21,7 @@ class Product extends Model implements HasMedia
}
public function registerMediaCollections(): void {
$this->addMediaCollection('default')
$this->addMediaCollection('images')
->useFallbackUrl('/images/fallback_product_image.png');
}

View File

@ -31,16 +31,11 @@ class ProductController extends Controller
public function store(StoreProductRequest $request) {
$product = Product::create($request->except('image'));
$product = Product::create($request->except('document'));
if ($request->has('image')) {
$tempFile = Upload::where('folder', $request->image)->first();
if ($tempFile) {
$product->addMedia(Storage::path('public/temp/' . $request->image . '/' . $tempFile->filename))->toMediaCollection();
Storage::deleteDirectory('public/temp/' . $request->image);
$tempFile->delete();
if ($request->has('document')) {
foreach ($request->input('document', []) as $file) {
$product->addMedia(storage_path('temp/dropzone/' . $file))->toMediaCollection('images');
}
}
@ -65,20 +60,23 @@ class ProductController extends Controller
public function update(UpdateProductRequest $request, Product $product) {
$product->update($request->except('image'));
$product->update($request->except('document'));
if ($request->has('image')) {
$tempFile = Upload::where('folder', $request->image)->first();
if ($product->getFirstMedia()) {
$product->getFirstMedia()->delete();
if ($request->has('document')) {
if (count($product->getMedia('images')) > 0) {
foreach ($product->getMedia('images') as $media) {
if (!in_array($media->file_name, $request->input('document', []))) {
$media->delete();
}
}
}
if ($tempFile) {
$product->addMedia(Storage::path('public/temp/' . $request->image . '/' . $tempFile->filename))->toMediaCollection();
$media = $product->getMedia('images')->pluck('file_name')->toArray();
Storage::deleteDirectory('public/temp/' . $request->image);
$tempFile->delete();
foreach ($request->input('document', []) as $file) {
if (count($media) === 0 || !in_array($file, $media)) {
$product->addMedia(storage_path('temp/dropzone/' . $file))->toMediaCollection('images');
}
}
}

View File

@ -2,10 +2,6 @@
@section('title', 'Create Product')
@section('third_party_stylesheets')
@include('includes.filepond-css')
@endsection
@section('breadcrumb')
<ol class="breadcrumb border-0 m-0">
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
@ -25,7 +21,7 @@
<button class="btn btn-primary">Create Product <i class="bi bi-check"></i></button>
</div>
</div>
<div class="col-lg-7">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div class="form-row">
@ -122,12 +118,16 @@
</div>
</div>
<div class="col-lg-5">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div class="form-group">
<label for="image">Product Image <span class="text-danger">*</span></label>
<input id="image" type="file" name="image" data-max-file-size="500KB">
<label for="image">Product Images <i class="bi bi-question-circle-fill text-info" data-toggle="tooltip" data-placement="top" title="Max Files: 3, Max File Size: 1MB"></i></label>
<div class="dropzone d-flex flex-wrap align-items-center justify-content-center" id="document-dropzone">
<div class="dz-message" data-dz-message>
<i class="bi bi-cloud-arrow-up"></i>
</div>
</div>
</div>
</div>
</div>
@ -137,8 +137,52 @@
</div>
@endsection
@section('third_party_scripts')
<script src="{{ asset('js/dropzone.js') }}"></script>
@endsection
@push('page_scripts')
@include('includes.filepond-js')
<script>
var uploadedDocumentMap = {}
Dropzone.options.documentDropzone = {
url: '{{ route('dropzone.upload') }}',
maxFilesize: 1,
acceptedFiles: '.jpg, .jpeg, .png',
maxFiles: 3,
addRemoveLinks: true,
dictRemoveFile: "<i class='bi bi-x-circle text-danger'></i> remove",
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
success: function (file, response) {
$('form').append('<input type="hidden" name="document[]" value="' + response.name + '">');
uploadedDocumentMap[file.name] = response.name;
},
removedfile: function (file) {
file.previewElement.remove();
var name = '';
if (typeof file.file_name !== 'undefined') {
name = file.file_name;
} else {
name = uploadedDocumentMap[file.name];
}
$('form').find('input[name="document[]"][value="' + name + '"]').remove();
},
init: function () {
@if(isset($product) && $product->getMedia('images'))
var files = {!! json_encode($product->getMedia('images')) !!};
for (var i in files) {
var file = files[i];
this.options.addedfile.call(this, file);
this.options.thumbnail.call(this, file, file.original_url);
file.previewElement.classList.add('dz-complete');
$('form').append('<input type="hidden" name="document[]" value="' + file.file_name + '">');
}
@endif
}
}
</script>
<script src="{{ asset('js/jquery-mask-money.js') }}"></script>
<script>
$(document).ready(function () {

View File

@ -2,10 +2,6 @@
@section('title', 'Edit Product')
@section('third_party_stylesheets')
@include('includes.filepond-css')
@endsection
@section('breadcrumb')
<ol class="breadcrumb border-0 m-0">
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
@ -26,8 +22,8 @@
<button class="btn btn-primary">Update Product <i class="bi bi-check"></i></button>
</div>
</div>
<div class="col-lg-8">
<div class="card h-100">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div class="form-row">
<div class="col-md-7">
@ -122,13 +118,16 @@
</div>
</div>
<div class="col-lg-4">
<div class="card h-100">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div class="form-group">
<label for="image">Product Image</label>
<img class="img-thumbnail img-fluid mb-3" src="{{ $product->getFirstMediaUrl() }}" alt="Product Image">
<input id="image" type="file" name="image" data-max-file-size="500KB">
<label for="image">Product Images <i class="bi bi-question-circle-fill text-info" data-toggle="tooltip" data-placement="top" title="Max Files: 3, Max File Size: 1MB"></i></label>
<div class="dropzone d-flex flex-wrap align-items-center justify-content-center" id="document-dropzone">
<div class="dz-message" data-dz-message>
<i class="bi bi-cloud-arrow-up"></i>
</div>
</div>
</div>
</div>
</div>
@ -138,8 +137,52 @@
</div>
@endsection
@section('third_party_scripts')
<script src="{{ asset('js/dropzone.js') }}"></script>
@endsection
@push('page_scripts')
@include('includes.filepond-js')
<script>
var uploadedDocumentMap = {}
Dropzone.options.documentDropzone = {
url: '{{ route('dropzone.upload') }}',
maxFilesize: 1,
acceptedFiles: '.jpg, .jpeg, .png',
maxFiles: 3,
addRemoveLinks: true,
dictRemoveFile: "<i class='bi bi-x-circle text-danger'></i> remove",
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
success: function (file, response) {
$('form').append('<input type="hidden" name="document[]" value="' + response.name + '">');
uploadedDocumentMap[file.name] = response.name;
},
removedfile: function (file) {
file.previewElement.remove();
var name = '';
if (typeof file.file_name !== 'undefined') {
name = file.file_name;
} else {
name = uploadedDocumentMap[file.name];
}
$('form').find('input[name="document[]"][value="' + name + '"]').remove();
},
init: function () {
@if(isset($product) && $product->getMedia('images'))
var files = {!! json_encode($product->getMedia('images')) !!};
for (var i in files) {
var file = files[i];
this.options.addedfile.call(this, file);
this.options.thumbnail.call(this, file, file.original_url);
file.previewElement.classList.add('dz-complete');
$('form').append('<input type="hidden" name="document[]" value="' + file.file_name + '">');
}
@endif
}
}
</script>
<script src="{{ asset('js/jquery-mask-money.js') }}"></script>
<script>
$(document).ready(function () {

View File

@ -18,7 +18,7 @@
</div>
</div>
<div class="row">
<div class="col-lg-7">
<div class="col-lg-8">
<div class="card h-100">
<div class="card-body">
<div class="table-responsive">
@ -77,10 +77,14 @@
</div>
</div>
<div class="col-lg-5">
<div class="col-lg-4">
<div class="card h-100">
<div class="card-body">
<img src="{{ $product->getFirstMediaUrl() }}" alt="Product Image" class="img-fluid img-thumbnail">
@forelse($product->getMedia('images') as $media)
<img src="{{ $media->getUrl() }}" alt="Product Image" class="img-fluid img-thumbnail mb-2">
@empty
<img src="{{ $product->getFirstMediaUrl('images') }}" alt="Product Image" class="img-fluid img-thumbnail mb-2">
@endforelse
</div>
</div>
</div>

View File

@ -24,7 +24,7 @@ class UploadController extends Controller
$file = Image::make($uploaded_file)->encode($uploaded_file->getClientOriginalExtension());
Storage::put('public/temp/' . $folder . '/' . $filename, $file);
Storage::put('temp/' . $folder . '/' . $filename, $file);
Upload::create([
'folder' => $folder,
@ -37,12 +37,33 @@ class UploadController extends Controller
return false;
}
public function filepondDelete(Request $request) {
$upload = Upload::where('folder', $request->getContent())->first();
Storage::deleteDirectory('public/temp/' . $upload->folder);
Storage::deleteDirectory('temp/' . $upload->folder);
$upload->delete();
return response(null);
}
public function dropzoneUpload(Request $request) {
$path = storage_path('temp/dropzone');
if (!file_exists($path)) {
mkdir($path, 0777, true);
}
$file = $request->file('file');
$name = now()->timestamp . '.' . trim($file->getClientOriginalExtension());
$file->move($path, $name);
return response()->json([
'name' => $name,
'original_name' => $file->getClientOriginalName(),
]);
}
}

View File

@ -13,6 +13,9 @@
Route::group(['middleware' => 'auth'], function () {
//Dropzone
Route::post('/dropzone/upload', 'UploadController@dropzoneUpload')->name('dropzone.upload');
//Filepond
Route::post('/filepond/upload', 'UploadController@filepondUpload')->name('filepond.upload');
Route::delete('/filepond/delete', 'UploadController@filepondDelete')->name('filepond.delete');

View File

@ -38,9 +38,9 @@ class ProfileController extends Controller
}
if ($tempFile) {
auth()->user()->addMedia(Storage::path('public/temp/' . $request->image . '/' . $tempFile->filename))->toMediaCollection('avatars');
auth()->user()->addMedia(Storage::path('temp/' . $request->image . '/' . $tempFile->filename))->toMediaCollection('avatars');
Storage::deleteDirectory('public/temp/' . $request->image);
Storage::deleteDirectory('temp/' . $request->image);
$tempFile->delete();
}
}

View File

@ -20,7 +20,7 @@ class ProductDataTable extends DataTable
return view('product::products.partials.actions', compact('data'));
})
->addColumn('product_image', function ($data) {
$url = $data->getFirstMediaUrl();
$url = $data->getFirstMediaUrl('images');
return '<img src="'.$url.'" border="0" width="50" class="img-thumbnail" align="center"/>';
})
->addColumn('product_price', function ($data) {

233
config/debugbar.php Normal file
View File

@ -0,0 +1,233 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Debugbar Settings
|--------------------------------------------------------------------------
|
| Debugbar is enabled by default, when debug is set to true in app.php.
| You can override the value by setting enable to true or false instead of null.
|
| You can provide an array of URI's that must be ignored (eg. 'api/*')
|
*/
'enabled' => env('DEBUGBAR_ENABLED', null),
'except' => [
'telescope*',
'horizon*',
],
/*
|--------------------------------------------------------------------------
| Storage settings
|--------------------------------------------------------------------------
|
| DebugBar stores data for session/ajax requests.
| You can disable this, so the debugbar stores data in headers/session,
| but this can cause problems with large data collectors.
| By default, file storage (in the storage folder) is used. Redis and PDO
| can also be used. For PDO, run the package migrations first.
|
*/
'storage' => [
'enabled' => true,
'driver' => 'file', // redis, file, pdo, socket, custom
'path' => storage_path('debugbar'), // For file driver
'connection' => null, // Leave null for default connection (Redis/PDO)
'provider' => '', // Instance of StorageInterface for custom driver
'hostname' => '127.0.0.1', // Hostname to use with the "socket" driver
'port' => 2304, // Port to use with the "socket" driver
],
/*
|--------------------------------------------------------------------------
| Vendors
|--------------------------------------------------------------------------
|
| Vendor files are included by default, but can be set to false.
| This can also be set to 'js' or 'css', to only include javascript or css vendor files.
| Vendor files are for css: font-awesome (including fonts) and highlight.js (css files)
| and for js: jquery and and highlight.js
| So if you want syntax highlighting, set it to true.
| jQuery is set to not conflict with existing jQuery scripts.
|
*/
'include_vendors' => true,
/*
|--------------------------------------------------------------------------
| Capture Ajax Requests
|--------------------------------------------------------------------------
|
| The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors),
| you can use this option to disable sending the data through the headers.
|
| Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools.
|
| Note for your request to be identified as ajax requests they must either send the header
| X-Requested-With with the value XMLHttpRequest (most JS libraries send this), or have application/json as a Accept header.
*/
'capture_ajax' => true,
'add_ajax_timing' => false,
/*
|--------------------------------------------------------------------------
| Custom Error Handler for Deprecated warnings
|--------------------------------------------------------------------------
|
| When enabled, the Debugbar shows deprecated warnings for Symfony components
| in the Messages tab.
|
*/
'error_handler' => false,
/*
|--------------------------------------------------------------------------
| Clockwork integration
|--------------------------------------------------------------------------
|
| The Debugbar can emulate the Clockwork headers, so you can use the Chrome
| Extension, without the server-side code. It uses Debugbar collectors instead.
|
*/
'clockwork' => false,
/*
|--------------------------------------------------------------------------
| DataCollectors
|--------------------------------------------------------------------------
|
| Enable/disable DataCollectors
|
*/
'collectors' => [
'phpinfo' => true, // Php version
'messages' => true, // Messages
'time' => true, // Time Datalogger
'memory' => true, // Memory usage
'exceptions' => true, // Exception displayer
'log' => true, // Logs from Monolog (merged in messages if enabled)
'db' => true, // Show database (PDO) queries and bindings
'views' => true, // Views with their data
'route' => true, // Current route information
'auth' => false, // Display Laravel authentication status
'gate' => true, // Display Laravel Gate checks
'session' => true, // Display session data
'symfony_request' => true, // Only one can be enabled..
'mail' => true, // Catch mail messages
'laravel' => false, // Laravel version and environment
'events' => false, // All events fired
'default_request' => false, // Regular or special Symfony request logger
'logs' => false, // Add the latest log messages
'files' => false, // Show the included files
'config' => false, // Display config settings
'cache' => false, // Display cache events
'models' => true, // Display models
'livewire' => true, // Display Livewire (when available)
],
/*
|--------------------------------------------------------------------------
| Extra options
|--------------------------------------------------------------------------
|
| Configure some DataCollectors
|
*/
'options' => [
'auth' => [
'show_name' => true, // Also show the users name/email in the debugbar
],
'db' => [
'with_params' => true, // Render SQL with the parameters substituted
'backtrace' => true, // Use a backtrace to find the origin of the query in your files.
'backtrace_exclude_paths' => [], // Paths to exclude from backtrace. (in addition to defaults)
'timeline' => false, // Add the queries to the timeline
'duration_background' => true, // Show shaded background on each query relative to how long it took to execute.
'explain' => [ // Show EXPLAIN output on queries
'enabled' => false,
'types' => ['SELECT'], // Deprecated setting, is always only SELECT
],
'hints' => false, // Show hints for common mistakes
'show_copy' => false, // Show copy button next to the query
],
'mail' => [
'full_log' => false,
],
'views' => [
'timeline' => false, // Add the views to the timeline (Experimental)
'data' => false, //Note: Can slow down the application, because the data can be quite large..
],
'route' => [
'label' => true, // show complete route on bar
],
'logs' => [
'file' => null,
],
'cache' => [
'values' => true, // collect cache values
],
],
/*
|--------------------------------------------------------------------------
| Inject Debugbar in Response
|--------------------------------------------------------------------------
|
| Usually, the debugbar is added just before </body>, by listening to the
| Response after the App is done. If you disable this, you have to add them
| in your template yourself. See http://phpdebugbar.com/docs/rendering.html
|
*/
'inject' => true,
/*
|--------------------------------------------------------------------------
| DebugBar route prefix
|--------------------------------------------------------------------------
|
| Sometimes you want to set route prefix to be used by DebugBar to load
| its resources from. Usually the need comes from misconfigured web server or
| from trying to overcome bugs like this: http://trac.nginx.org/nginx/ticket/97
|
*/
'route_prefix' => '_debugbar',
/*
|--------------------------------------------------------------------------
| DebugBar route domain
|--------------------------------------------------------------------------
|
| By default DebugBar route served from the same domain that request served.
| To override default domain, specify it as a non-empty value.
*/
'route_domain' => null,
/*
|--------------------------------------------------------------------------
| DebugBar theme
|--------------------------------------------------------------------------
|
| Switches between light and dark theme. If set to auto it will respect system preferences
| Possible values: auto, light, dark
*/
'theme' => env('DEBUGBAR_THEME', 'auto'),
/*
|--------------------------------------------------------------------------
| Backtrace stack limit
|--------------------------------------------------------------------------
|
| By default, the DebugBar limits the number of frames returned by the 'debug_backtrace()' function.
| If you need larger stacktraces, you can increase this number. Setting it to 0 will result in no limit.
*/
'debug_backtrace_limit' => 50,
];

18786
public/css/app.css vendored

File diff suppressed because one or more lines are too long

396
public/css/dropzone.css vendored Normal file
View File

@ -0,0 +1,396 @@
/*
* The MIT License
* Copyright (c) 2012 Matias Meno <m@tias.me>
*/
@-webkit-keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30%, 70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); }
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px); } }
@-moz-keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30%, 70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); }
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px); } }
@keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30%, 70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); }
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px); } }
@-webkit-keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); } }
@-moz-keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); } }
@keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); } }
@-webkit-keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); }
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1); }
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); } }
@-moz-keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); }
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1); }
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); } }
@keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); }
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1); }
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); } }
.dropzone, .dropzone * {
box-sizing: border-box; }
.dropzone {
min-height: 150px;
border: 2px solid rgba(0, 0, 0, 0.3);
background: white;
padding: 20px 20px; }
.dropzone.dz-clickable {
cursor: pointer; }
.dropzone.dz-clickable * {
cursor: default; }
.dropzone.dz-clickable .dz-message, .dropzone.dz-clickable .dz-message * {
cursor: pointer; }
.dropzone.dz-started .dz-message {
display: none; }
.dropzone.dz-drag-hover {
border-style: solid; }
.dropzone.dz-drag-hover .dz-message {
opacity: 0.5; }
.dropzone .dz-message {
text-align: center;
margin: 2em 0; }
.dropzone .dz-message .dz-button {
background: none;
color: inherit;
border: none;
padding: 0;
font: inherit;
cursor: pointer;
outline: inherit; }
.dropzone .dz-preview {
position: relative;
display: inline-block;
vertical-align: top;
margin: 16px;
min-height: 100px; }
.dropzone .dz-preview:hover {
z-index: 1000; }
.dropzone .dz-preview:hover .dz-details {
opacity: 1; }
.dropzone .dz-preview.dz-file-preview .dz-image {
border-radius: 20px;
background: #999;
background: linear-gradient(to bottom, #eee, #ddd); }
.dropzone .dz-preview.dz-file-preview .dz-details {
opacity: 1; }
.dropzone .dz-preview.dz-image-preview {
background: white; }
.dropzone .dz-preview.dz-image-preview .dz-details {
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
-ms-transition: opacity 0.2s linear;
-o-transition: opacity 0.2s linear;
transition: opacity 0.2s linear; }
.dropzone .dz-preview .dz-remove {
font-size: 14px;
text-align: center;
display: block;
cursor: pointer;
border: none; }
.dropzone .dz-preview .dz-remove:hover {
text-decoration: underline; }
.dropzone .dz-preview:hover .dz-details {
opacity: 1; }
.dropzone .dz-preview .dz-details {
z-index: 20;
position: absolute;
top: 0;
left: 0;
opacity: 0;
font-size: 13px;
min-width: 100%;
max-width: 100%;
padding: 2em 1em;
text-align: center;
color: rgba(0, 0, 0, 0.9);
line-height: 150%; }
.dropzone .dz-preview .dz-details .dz-size {
margin-bottom: 1em;
font-size: 16px; }
.dropzone .dz-preview .dz-details .dz-filename {
white-space: nowrap; }
.dropzone .dz-preview .dz-details .dz-filename:hover span {
border: 1px solid rgba(200, 200, 200, 0.8);
background-color: rgba(255, 255, 255, 0.8); }
.dropzone .dz-preview .dz-details .dz-filename:not(:hover) {
overflow: hidden;
text-overflow: ellipsis; }
.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span {
border: 1px solid transparent; }
.dropzone .dz-preview .dz-details .dz-filename span, .dropzone .dz-preview .dz-details .dz-size span {
background-color: rgba(255, 255, 255, 0.4);
padding: 0 0.4em;
border-radius: 3px; }
.dropzone .dz-preview:hover .dz-image img {
-webkit-transform: scale(1.05, 1.05);
-moz-transform: scale(1.05, 1.05);
-ms-transform: scale(1.05, 1.05);
-o-transform: scale(1.05, 1.05);
transform: scale(1.05, 1.05);
-webkit-filter: blur(8px);
filter: blur(8px); }
.dropzone .dz-preview .dz-image {
border-radius: 20px;
overflow: hidden;
width: 120px;
height: 120px;
position: relative;
display: block;
z-index: 10; }
.dropzone .dz-preview .dz-image img {
display: block; }
.dropzone .dz-preview.dz-success .dz-success-mark {
-webkit-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-moz-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-ms-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-o-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); }
.dropzone .dz-preview.dz-error .dz-error-mark {
opacity: 1;
-webkit-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-moz-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-ms-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-o-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); }
.dropzone .dz-preview .dz-success-mark, .dropzone .dz-preview .dz-error-mark {
pointer-events: none;
opacity: 0;
z-index: 500;
position: absolute;
display: block;
top: 50%;
left: 50%;
margin-left: -27px;
margin-top: -27px; }
.dropzone .dz-preview .dz-success-mark svg, .dropzone .dz-preview .dz-error-mark svg {
display: block;
width: 54px;
height: 54px; }
.dropzone .dz-preview.dz-processing .dz-progress {
opacity: 1;
-webkit-transition: all 0.2s linear;
-moz-transition: all 0.2s linear;
-ms-transition: all 0.2s linear;
-o-transition: all 0.2s linear;
transition: all 0.2s linear; }
.dropzone .dz-preview.dz-complete .dz-progress {
opacity: 0;
-webkit-transition: opacity 0.4s ease-in;
-moz-transition: opacity 0.4s ease-in;
-ms-transition: opacity 0.4s ease-in;
-o-transition: opacity 0.4s ease-in;
transition: opacity 0.4s ease-in; }
.dropzone .dz-preview:not(.dz-processing) .dz-progress {
-webkit-animation: pulse 6s ease infinite;
-moz-animation: pulse 6s ease infinite;
-ms-animation: pulse 6s ease infinite;
-o-animation: pulse 6s ease infinite;
animation: pulse 6s ease infinite; }
.dropzone .dz-preview .dz-progress {
opacity: 1;
z-index: 1000;
pointer-events: none;
position: absolute;
height: 16px;
left: 50%;
top: 50%;
margin-top: -8px;
width: 80px;
margin-left: -40px;
background: rgba(255, 255, 255, 0.9);
-webkit-transform: scale(1);
border-radius: 8px;
overflow: hidden; }
.dropzone .dz-preview .dz-progress .dz-upload {
background: #333;
background: linear-gradient(to bottom, #666, #444);
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 0;
-webkit-transition: width 300ms ease-in-out;
-moz-transition: width 300ms ease-in-out;
-ms-transition: width 300ms ease-in-out;
-o-transition: width 300ms ease-in-out;
transition: width 300ms ease-in-out; }
.dropzone .dz-preview.dz-error .dz-error-message {
display: block; }
.dropzone .dz-preview.dz-error:hover .dz-error-message {
opacity: 1;
pointer-events: auto; }
.dropzone .dz-preview .dz-error-message {
pointer-events: none;
z-index: 1000;
position: absolute;
display: block;
display: none;
opacity: 0;
-webkit-transition: opacity 0.3s ease;
-moz-transition: opacity 0.3s ease;
-ms-transition: opacity 0.3s ease;
-o-transition: opacity 0.3s ease;
transition: opacity 0.3s ease;
border-radius: 8px;
font-size: 13px;
top: 130px;
left: -10px;
width: 140px;
background: #be2626;
background: linear-gradient(to bottom, #be2626, #a92222);
padding: 0.5em 1.2em;
color: white; }
.dropzone .dz-preview .dz-error-message:after {
content: '';
position: absolute;
top: -6px;
left: 64px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #be2626; }

53186
public/js/app.js vendored

File diff suppressed because one or more lines are too long

View File

@ -41,6 +41,27 @@
* Date: 2021-03-02T17:08Z
*/
/*!
DataTables Bootstrap 4 integration
©2011-2017 SpryMedia Ltd - datatables.net/license
*/
/*! Bootstrap integration for DataTables' Buttons
* ©2016 SpryMedia Ltd - datatables.net/license
*/
/*! Buttons for DataTables 1.7.1
* ©2016-2021 SpryMedia Ltd - datatables.net/license
*/
/*! DataTables 1.10.25
* ©2008-2021 SpryMedia Ltd - datatables.net/license
*/
/*! DataTables Bootstrap 4 integration
* ©2011-2017 SpryMedia Ltd - datatables.net/license
*/
/**
* @license
* Lodash <https://lodash.com/>

View File

@ -1,75 +1 @@
/******/ (() => { // webpackBootstrap
var __webpack_exports__ = {};
/*!**************************************!*\
!*** ./resources/js/chart-config.js ***!
\**************************************/
$(document).ready(function () {
var salesPurchasesBar = document.getElementById('salesPurchasesChart');
$.get('/sales-purchases/chart-data', function (response) {
var salesPurchasesChart = new Chart(salesPurchasesBar, {
type: 'bar',
data: {
labels: response.sales.original.days,
datasets: [{
label: 'Sales',
data: response.sales.original.data,
backgroundColor: ['#6366F1'],
borderColor: ['#6366F1'],
borderWidth: 1
}, {
label: 'Purchases',
data: response.purchases.original.data,
backgroundColor: ['#A5B4FC'],
borderColor: ['#A5B4FC'],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
});
var overviewChart = document.getElementById('currentMonthChart');
$.get('/current-month/chart-data', function (response) {
var currentMonthChart = new Chart(overviewChart, {
type: 'doughnut',
data: {
labels: ['Sales', 'Purchases', 'Expenses'],
datasets: [{
data: [response.sales, response.purchases, response.expenses],
backgroundColor: ['#F59E0B', '#0284C7', '#EF4444'],
hoverBackgroundColor: ['#F59E0B', '#0284C7', '#EF4444']
}]
}
});
});
var paymentChart = document.getElementById('paymentChart');
$.get('/payment-flow/chart-data', function (response) {
console.log(response);
var cashflowChart = new Chart(paymentChart, {
type: 'line',
data: {
labels: response.months,
datasets: [{
label: 'Payment Sent',
data: response.payment_sent,
fill: false,
borderColor: '#EA580C',
tension: 0
}, {
label: 'Payment Received',
data: response.payment_received,
fill: false,
borderColor: '#2563EB',
tension: 0
}]
}
});
});
});
/******/ })()
;
$(document).ready((function(){var a=document.getElementById("salesPurchasesChart");$.get("/sales-purchases/chart-data",(function(e){new Chart(a,{type:"bar",data:{labels:e.sales.original.days,datasets:[{label:"Sales",data:e.sales.original.data,backgroundColor:["#6366F1"],borderColor:["#6366F1"],borderWidth:1},{label:"Purchases",data:e.purchases.original.data,backgroundColor:["#A5B4FC"],borderColor:["#A5B4FC"],borderWidth:1}]},options:{scales:{y:{beginAtZero:!0}}}})}));var e=document.getElementById("currentMonthChart");$.get("/current-month/chart-data",(function(a){new Chart(e,{type:"doughnut",data:{labels:["Sales","Purchases","Expenses"],datasets:[{data:[a.sales,a.purchases,a.expenses],backgroundColor:["#F59E0B","#0284C7","#EF4444"],hoverBackgroundColor:["#F59E0B","#0284C7","#EF4444"]}]}})}));var t=document.getElementById("paymentChart");$.get("/payment-flow/chart-data",(function(a){console.log(a),new Chart(t,{type:"line",data:{labels:a.months,datasets:[{label:"Payment Sent",data:a.payment_sent,fill:!1,borderColor:"#EA580C",tension:0},{label:"Payment Received",data:a.payment_received,fill:!1,borderColor:"#2563EB",tension:0}]}})}))}));

3830
public/js/dropzone.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,28 @@
box-shadow: 0 1px 1px 0 rgb(60 75 100 / 14%), 0 2px 1px -1px rgb(60 75 100 / 12%), 0 1px 3px 0 rgb(60 75 100 / 20%);
}
.dropzone {
border: 2px dashed #3B82F6;
border-radius: 5px;
background: #DBEAFE;
}
.dz-preview {
background: #EFF6FF !important;
border-radius: 20px;
}
.dz-remove {
color: #333;
}
.dropzone i.bi.bi-cloud-arrow-up {
font-size: 5rem;
color: #60A5FA;
}
.dropzone .dz-message {
color: rgba(0,0,0,.54);
font-weight: 500;
font-size: initial;
}
table {
width: 990px !important;
}

View File

@ -5,6 +5,8 @@
<title>@yield('title') || {{ config('app.name') }}</title>
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
<!-- Dropezone CSS -->
<link rel="stylesheet" href="{{ asset('css/dropzone.css') }}">
<!-- CoreUI CSS -->
<link rel="stylesheet" href="{{ mix('css/app.css') }}" crossorigin="anonymous">
<!-- Bootstrap Icons -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB