mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Enable downloads for the client
This commit is contained in:
parent
aa7ebcee3e
commit
4eb5490984
24
app/Http/Controllers/ClientPortal/DownloadController.php
Normal file
24
app/Http/Controllers/ClientPortal/DownloadController.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\ClientPortal;
|
||||
|
||||
use App\Models\Document;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class DownloadController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return render('downloads.index');
|
||||
}
|
||||
}
|
26
app/Http/Livewire/DownloadsTable.php
Normal file
26
app/Http/Livewire/DownloadsTable.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Document;
|
||||
use App\Utils\Traits\WithSorting;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
class DownloadsTable extends Component
|
||||
{
|
||||
use WithPagination, WithSorting;
|
||||
|
||||
public $per_page = 10;
|
||||
|
||||
public function render()
|
||||
{
|
||||
$query = auth()->user()->client->documents()
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||
->paginate($this->per_page);
|
||||
|
||||
return render('components.livewire.downloads-table', [
|
||||
'downloads' => $query,
|
||||
]);
|
||||
}
|
||||
}
|
@ -31,8 +31,6 @@ class InvoicesTable extends Component
|
||||
|
||||
public function render()
|
||||
{
|
||||
DB::enableQueryLog();
|
||||
|
||||
$query = Invoice::query()
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc');
|
||||
|
||||
|
@ -67,6 +67,7 @@ class PortalComposer
|
||||
$data[] = [ 'title' => ctrans('texts.quotes'), 'url' => 'client.quotes.index', 'icon' => 'align-left'];
|
||||
$data[] = [ 'title' => ctrans('texts.credits'), 'url' => 'client.credits.index', 'icon' => 'credit-card'];
|
||||
$data[] = [ 'title' => ctrans('texts.payment_methods'), 'url' => 'client.payment_methods.index', 'icon' => 'shield'];
|
||||
$data[] = [ 'title' => ctrans('texts.downloads'), 'url' => 'client.downloads.index', 'icon' => 'download'];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
2
public/css/app.css
vendored
2
public/css/app.css
vendored
File diff suppressed because one or more lines are too long
1
public/images/svg/download.svg
Normal file
1
public/images/svg/download.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-download"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
|
After Width: | Height: | Size: 365 B |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"/js/app.js": "/js/app.js?id=baf7fef12d5e65c3d9ff",
|
||||
"/css/app.css": "/css/app.css?id=733876eca1ef8a36e2c3",
|
||||
"/css/app.css": "/css/app.css?id=79bfe92f3563a0cce914",
|
||||
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=d244486b16dc6f94a726",
|
||||
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=d7e708d66a9c769b4c6e",
|
||||
"/js/clients/payment_methods/authorize-ach.js": "/js/clients/payment_methods/authorize-ach.js?id=9e6495d9ae236b3cb5ad",
|
||||
|
@ -582,7 +582,7 @@ return [
|
||||
'hours' => 'Hours',
|
||||
'task_details' => 'Task Details',
|
||||
'duration' => 'Duration',
|
||||
'time_log'=> 'Time Log',
|
||||
'time_log' => 'Time Log',
|
||||
'end_time' => 'End Time',
|
||||
'end' => 'End',
|
||||
'invoiced' => 'Invoiced',
|
||||
@ -1824,7 +1824,7 @@ return [
|
||||
'industry_Transportation' => 'Transportation',
|
||||
'industry_Travel & Luxury' => 'Travel & Luxury',
|
||||
'industry_Other' => 'Other',
|
||||
'industry_Photography' =>'Photography',
|
||||
'industry_Photography' => 'Photography',
|
||||
|
||||
'view_client_portal' => 'View client portal',
|
||||
'view_portal' => 'View Portal',
|
||||
@ -1910,7 +1910,7 @@ return [
|
||||
'toggle_history' => 'Toggle History',
|
||||
'unassigned' => 'Unassigned',
|
||||
'task' => 'Task',
|
||||
'task_details'=>'Task Details',
|
||||
'task_details' => 'Task Details',
|
||||
'contact_name' => 'Contact Name',
|
||||
'city_state_postal' => 'City/State/Postal',
|
||||
'custom_field' => 'Custom Field',
|
||||
@ -3243,4 +3243,12 @@ return [
|
||||
'node_status_not_found' => 'I could not find Node anywhere. Is it installed?',
|
||||
'npm_status_not_found' => 'I could not find NPM anywhere. Is it installed?',
|
||||
'locked_invoice' => 'This invoice is locked and unable to be modified',
|
||||
|
||||
'downloads' => 'Downloads',
|
||||
'resource' => 'Resource',
|
||||
|
||||
'document_details' => 'Details about the document.',
|
||||
|
||||
'width' => 'Width',
|
||||
'height' => 'Height',
|
||||
];
|
||||
|
@ -0,0 +1,83 @@
|
||||
<div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<span class="mr-2 text-sm hidden md:block">{{ ctrans('texts.per_page') }}</span>
|
||||
<select wire:model="per_page" class="form-select py-1 text-sm">
|
||||
<option>5</option>
|
||||
<option selected>10</option>
|
||||
<option>15</option>
|
||||
<option>20</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="-my-2 py-2 overflow-x-auto sm:-mx-6 sm:px-6 lg:-mx-8 lg:px-8">
|
||||
<div class="align-middle inline-block min-w-full overflow-hidden rounded">
|
||||
<table class="min-w-full shadow rounded border border-gray-200 mt-4 credits-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
|
||||
<span role="button" wire:click="sortBy('name')" class="cursor-pointer">
|
||||
{{ ctrans('texts.name') }}
|
||||
</span>
|
||||
</th>
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
|
||||
<span role="button" wire:click="sortBy('documentable_type')" class="cursor-pointer">
|
||||
{{ ctrans('texts.resource') }}
|
||||
</span>
|
||||
</th>
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
|
||||
<span role="button" wire:click="sortBy('type')" class="cursor-pointer">
|
||||
{{ ctrans('texts.type') }}
|
||||
</span>
|
||||
</th>
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
|
||||
<span role="button" wire:click="sortBy('size')" class="cursor-pointer">
|
||||
{{ ctrans('texts.size') }}
|
||||
</span>
|
||||
</th>
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
|
||||
{{ ctrans('texts.download') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($downloads as $download)
|
||||
<tr class="bg-white group hover:bg-gray-100">
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
|
||||
{{ Illuminate\Support\Str::limit($download->name, 20) }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
|
||||
{{ ((new \ReflectionClass($download->documentable))->getShortName()) }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
|
||||
{{ App\Models\Document::$types[$download->type]['mime'] }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
|
||||
{{ $download->size / 1000 }} kB
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
|
||||
<a href="{{ $download->generateUrl() }}" class="text-black hover:text-blue-600" download>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-download-cloud"><polyline points="8 17 12 21 16 17"></polyline><line x1="12" y1="12" x2="12" y2="21"></line><path d="M20.88 18.09A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.29"></path></svg>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr class="bg-white group hover:bg-gray-100">
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500" colspan="100%">
|
||||
{{ ctrans('texts.no_results') }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center md:justify-between mt-6 mb-6">
|
||||
@if($downloads->total() > 0)
|
||||
<span class="text-gray-700 text-sm hidden md:block">
|
||||
{{ ctrans('texts.showing_x_of', ['first' => $downloads->firstItem(), 'last' => $downloads->lastItem(), 'total' => $downloads->total()]) }}
|
||||
</span>
|
||||
@endif
|
||||
{{ $downloads->links() }}
|
||||
</div>
|
||||
</div>
|
16
resources/views/portal/ninja2020/downloads/index.blade.php
Normal file
16
resources/views/portal/ninja2020/downloads/index.blade.php
Normal file
@ -0,0 +1,16 @@
|
||||
@extends('portal.ninja2020.layout.app')
|
||||
@section('meta_title', ctrans('texts.downloads'))
|
||||
|
||||
@section('header')
|
||||
@if($errors->any())
|
||||
<div class="alert alert-failure mb-4">
|
||||
@foreach($errors->all() as $error)
|
||||
<p>{{ $error }}</p>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@endsection
|
||||
|
||||
@section('body')
|
||||
@livewire('downloads-table')
|
||||
@endsection
|
@ -60,6 +60,8 @@ Route::group(['middleware' => ['auth:contact','locale'], 'prefix' => 'client', '
|
||||
|
||||
Route::get('client/switch_company/{contact}', 'ClientPortal\SwitchCompanyController')->name('switch_company');
|
||||
|
||||
Route::resource('downloads', 'ClientPortal\DownloadController');
|
||||
|
||||
Route::get('logout', 'Auth\ContactLoginController@logout')->name('logout');
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user