mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-31 23:24:36 -04:00
view composers for client portal
This commit is contained in:
parent
baabfb9a06
commit
1823a23b2d
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Filters;
|
namespace App\Filters;
|
||||||
|
|
||||||
|
use App\Models\Invoice;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
|
||||||
@ -113,16 +114,31 @@ class InvoiceFilters extends QueryFilters
|
|||||||
* @param $company_id The company Id
|
* @param $company_id The company Id
|
||||||
* @return Illuminate\Database\Query\Builder
|
* @return Illuminate\Database\Query\Builder
|
||||||
*/
|
*/
|
||||||
public function entityFilter()
|
public function entityFilter()
|
||||||
{
|
{
|
||||||
|
|
||||||
if(auth('contact')->user())
|
if(auth('contact')->user())
|
||||||
return $this->builder->whereCompanyId(auth('contact')->user()->company->id);
|
return $this->contactViewFilter();
|
||||||
else
|
else
|
||||||
return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We need additional filters when showing invoices for the
|
||||||
|
* client portal. Need to automatically exclude drafts and cancelled invoices
|
||||||
|
*
|
||||||
|
* @return Illuminate\Database\Query\Builder
|
||||||
|
*/
|
||||||
|
private function contactViewFilter() : Builder
|
||||||
|
{
|
||||||
|
|
||||||
|
return $this->builder
|
||||||
|
->whereCompanyId(auth('contact')->user()->company->id)
|
||||||
|
->whereNotIn('status_id', [Invoice::STATUS_DRAFT, Invoice::STATUS_CANCELLED]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
85
app/Http/Controllers/ClientPortal/InvoiceController.php
Normal file
85
app/Http/Controllers/ClientPortal/InvoiceController.php
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Filters\InvoiceFilters;
|
||||||
|
use App\Jobs\Entity\ActionEntity;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Repositories\BaseRepository;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class InvoiceController
|
||||||
|
* @package App\Http\Controllers\ClientPortal\InvoiceController
|
||||||
|
*/
|
||||||
|
|
||||||
|
class InvoiceController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InvoiceController constructor.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the list of Invoices
|
||||||
|
*
|
||||||
|
* @param \App\Filters\InvoiceFilters $filters The filters
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function index(InvoiceFilters $filters)
|
||||||
|
{
|
||||||
|
|
||||||
|
$invoices = Invoice::filter($filters);
|
||||||
|
|
||||||
|
return $this->listResponse($invoices);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*
|
||||||
|
* @param \App\Models\Invoice $invoice The invoice
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function show(Invoice $invoice)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform bulk actions on the list view
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function bulk()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -26,23 +26,36 @@ class PortalComposer
|
|||||||
* @param View $view
|
* @param View $view
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function compose(View $view)
|
public function compose(View $view) :void
|
||||||
{
|
{
|
||||||
$view->with('header', $this->portalData());
|
$view->with('portal', $this->portalData());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function portalData()
|
private function portalData() :array
|
||||||
{
|
{
|
||||||
if(!auth()->user())
|
if(!auth()->user())
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
$data = [];
|
$data['sidebar'] = $this->sidebarMenu();
|
||||||
|
$data['header'] = [];
|
||||||
|
$data['footer'] = [];
|
||||||
|
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function sidebarMenu() :array
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
$data[] = [ 'title' => ctrans('texts.dashboard'), 'url' => 'client.dashboard', 'icon' => 'fa fa-tachometer'];
|
||||||
|
$data[] = [ 'title' => ctrans('texts.invoices'), 'url' => 'client.invoices.index', 'icon' => 'fa fa-file-excel-o'];
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -18,4 +18,12 @@ namespace App\Models\Presenters;
|
|||||||
class ClientContactPresenter extends EntityPresenter
|
class ClientContactPresenter extends EntityPresenter
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function name()
|
||||||
|
{
|
||||||
|
return $this->entity->first_name . ' ' . $this->entity->last_name;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
<ul class="nav navbar-nav ml-auto">
|
<ul class="nav navbar-nav ml-auto">
|
||||||
<li class="nav-item dropdown d-md-down-none" style="padding-left:20px; padding-right: 20px;">
|
<li class="nav-item dropdown d-md-down-none" style="padding-left:20px; padding-right: 20px;">
|
||||||
<a class="nav-link" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
|
||||||
<i class="icon-list"></i>
|
<i class="fa fa-envelope" aria-hidden="true"></i>
|
||||||
<span class="badge badge-pill badge-warning">15</span>
|
<span class="badge badge-pill badge-warning">15</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu dropdown-menu-right dropdown-menu-lg">
|
<div class="dropdown-menu dropdown-menu-right dropdown-menu-lg">
|
||||||
<div class="dropdown-header text-center">
|
<div class="dropdown-header text-center">
|
||||||
<strong>You have 5 pending tasks</strong>
|
<strong>@lang('texts.notifications')</strong>
|
||||||
</div>
|
</div>
|
||||||
<a class="dropdown-item" href="#">
|
<a class="dropdown-item" href="#">
|
||||||
<div class="small mb-1">Mr Miyagi todos
|
<div class="small mb-1">Mr Miyagi todos
|
||||||
@ -31,88 +31,29 @@
|
|||||||
<div class="progress-bar bg-info" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
<div class="progress-bar bg-info" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item" href="#">
|
|
||||||
<div class="small mb-1">First, wash all car.
|
|
||||||
<span class="float-right">
|
|
||||||
<strong>25%</strong>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<span class="progress progress-xs">
|
|
||||||
<div class="progress-bar bg-danger" role="progressbar" style="width: 25%" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item" href="#">
|
|
||||||
<div class="small mb-1">Then wax. Wax on...
|
|
||||||
<span class="float-right">
|
|
||||||
<strong>50%</strong>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<span class="progress progress-xs">
|
|
||||||
<div class="progress-bar bg-warning" role="progressbar" style="width: 50%" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item" href="#">
|
|
||||||
<div class="small mb-1">No questions!
|
|
||||||
<span class="float-right">
|
|
||||||
<strong>75%</strong>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<span class="progress progress-xs">
|
|
||||||
<div class="progress-bar bg-info" role="progressbar" style="width: 75%" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"></div>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item" href="#">
|
|
||||||
<div class="small mb-1">Wax on... wax off. Wax on... wax off.
|
|
||||||
<span class="float-right">
|
|
||||||
<strong>100%</strong>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<span class="progress progress-xs">
|
|
||||||
<div class="progress-bar bg-success" role="progressbar" style="width: 100%" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item text-center" href="#">
|
<a class="dropdown-item text-center" href="#">
|
||||||
<strong>View all tasks</strong>
|
<strong>@lang('texts.more')</strong>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav-item dropdown d-md-down-none" style="padding-left:20px; padding-right: 20px;">
|
|
||||||
<a class="nav-link" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
|
|
||||||
<i class="fa fa-building" aria-hidden="true"></i>
|
|
||||||
</a>
|
|
||||||
<div class="dropdown-menu dropdown-menu-right dropdown-menu-lg">
|
|
||||||
<div class="dropdown-header text-center">
|
|
||||||
<strong>@lang('texts.manage_companies')</strong>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
|
||||||
<img class="img-avatar" src="/images/logo.png" alt=""> {{ auth()->user()->first_name }}
|
<img class="img-avatar" src="/images/logo.png" alt=""> {{ auth()->user()->present()->name() }}
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu dropdown-menu-right">
|
<div class="dropdown-menu dropdown-menu-right">
|
||||||
<div class="dropdown-header text-center">
|
<div class="dropdown-header text-center">
|
||||||
<strong>Settings</strong>
|
<strong>@lang('texts.settings')</strong>
|
||||||
</div>
|
</div>
|
||||||
<a class="dropdown-item" href="#">
|
<a class="dropdown-item" href="#">
|
||||||
<i class="fa fa-user"></i> Profile</a>
|
<i class="fa fa-user"></i> @lang('texts.profile')</a>
|
||||||
<a class="dropdown-item" href="">
|
<a class="dropdown-item" href="">
|
||||||
<i class="fa fa-wrench"></i> @lang('texts.settings')</a>
|
<i class="fa fa-wrench"></i> @lang('texts.settings')</a>
|
||||||
|
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item" href="">
|
<a class="dropdown-item" href="{{ route('client.logout') }}">
|
||||||
<i class="fa fa-lock"></i> Logout</a>
|
<i class="fa fa-lock"></i> @lang('texts.logout')</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<button class="navbar-toggler aside-menu-toggler d-md-down-none" type="button" data-toggle="aside-menu-lg-show">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<button class="navbar-toggler aside-menu-toggler d-lg-none" type="button" data-toggle="aside-menu-show">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
</header>
|
</header>
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
@yield('head')
|
@yield('head')
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@include('portal.default.header', $header)
|
@include('portal.default.header')
|
||||||
@yield('header')
|
@yield('header')
|
||||||
|
|
||||||
@include('portal.default.sidebar')
|
@include('portal.default.sidebar')
|
||||||
|
@ -2,67 +2,13 @@
|
|||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
<nav class="sidebar-nav">
|
<nav class="sidebar-nav">
|
||||||
<ul class="nav">
|
<ul class="nav">
|
||||||
|
@foreach($portal['sidebar'] as $row)
|
||||||
<li class="nav-item ">
|
<li class="nav-item ">
|
||||||
<a class="nav-link" href="{{ route('dashboard.index') }}">
|
<a class="nav-link" href="{{ $row['url'] }}">
|
||||||
<i class="nav-icon icon-speedometer"></i> @lang('texts.dashboard')
|
<i class="{{$row['icon']}}"></i> {{ $row['title'] }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@endforeach
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/clients">
|
|
||||||
<i class="nav-icon icon-user"></i> @lang('texts.clients')</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="{{ route('invoices.index') }}">
|
|
||||||
<i class="nav-icon icon-notebook"></i> @lang('texts.invoices')</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="typography.html">
|
|
||||||
<i class="nav-icon icon-wallet"></i> @lang('texts.payments')</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="typography.html">
|
|
||||||
<i class="nav-icon icon-docs"></i> @lang('texts.recurring')</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="typography.html">
|
|
||||||
<i class="nav-icon icon-badge"></i> @lang('texts.credits')</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="typography.html">
|
|
||||||
<i class="nav-icon icon-vector"></i> @lang('texts.quotes')</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="typography.html">
|
|
||||||
<i class="nav-icon icon-wrench"></i> @lang('texts.projects')</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="typography.html">
|
|
||||||
<i class="nav-icon icon-grid"></i> @lang('texts.tasks')</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="typography.html">
|
|
||||||
<i class="nav-icon icon-envelope-open"></i> @lang('texts.expenses')</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="typography.html">
|
|
||||||
<i class="nav-icon icon-bell"></i> @lang('texts.vendors')</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="typography.html">
|
|
||||||
<i class="nav-icon icon-printer"></i> @lang('texts.reports')</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<button class="sidebar-minimizer brand-minimizer" type="button"></button>
|
<button class="sidebar-minimizer brand-minimizer" type="button"></button>
|
||||||
|
@ -13,6 +13,7 @@ Route::post('client/password/reset', 'Auth\ContactResetPasswordController@reset'
|
|||||||
Route::group(['middleware' => ['auth:contact'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
Route::group(['middleware' => ['auth:contact'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
||||||
|
|
||||||
Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit
|
Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit
|
||||||
|
Route::get('invoices', 'ClientPortal\InvoiceController@index')->name('invoices.index'); // name = (dashboard. index / create / show / update / destroy / edit
|
||||||
|
|
||||||
Route::get('logout', 'Auth\ContactLoginController@logout')->name('logout');
|
Route::get('logout', 'Auth\ContactLoginController@logout')->name('logout');
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user