1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-08 12:12:48 +01:00

Added client dashboard

This commit is contained in:
Hillel Coren 2015-10-13 18:44:01 +03:00
parent 2dfc053cbc
commit aef0fe8430
34 changed files with 832 additions and 1833 deletions

View File

@ -120,13 +120,10 @@ module.exports = function(grunt) {
src: [
'public/vendor/bootstrap/dist/css/bootstrap.min.css',
'public/vendor/font-awesome/css/font-awesome.min.css',
/*
'public/css/bootstrap.splash.css',
'public/css/splash.css',
*/
'public/css/bootstrap-combobox.css',
'public/vendor/datatables/media/css/jquery.dataTables.css',
'public/vendor/datatables-bootstrap3/BS3/assets/css/datatables.css',
'public/css/public.style.css',
],
dest: 'public/css/built.public.css',
nonull: true,

View File

@ -20,14 +20,7 @@ class ActivityController extends BaseController
->addColumn('activities.id', function ($model) { return Utils::timestampToDateTimeString(strtotime($model->created_at)); })
->addColumn('message', function ($model) { return Utils::decodeActivity($model->message); })
->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id); })
->addColumn('adjustment', function ($model) { return $model->adjustment != 0 ? self::wrapAdjustment($model->adjustment, $model->currency_id) : ''; })
->addColumn('adjustment', function ($model) { return $model->adjustment != 0 ? Utils::wrapAdjustment($model->adjustment, $model->currency_id) : ''; })
->make();
}
private function wrapAdjustment($adjustment, $currencyId)
{
$class = $adjustment <= 0 ? 'success' : 'default';
$adjustment = Utils::formatMoney($adjustment, $currencyId);
return "<h4><div class=\"label label-{$class}\">$adjustment</div></h4>";
}
}

View File

@ -76,28 +76,6 @@ class InvoiceController extends BaseController
return View::make('list', $data);
}
public function clientIndex()
{
$invitationKey = Session::get('invitation_key');
if (!$invitationKey) {
app()->abort(404);
}
$invitation = Invitation::with('account')->where('invitation_key', '=', $invitationKey)->first();
$account = $invitation->account;
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [
'color' => $color,
'hideLogo' => $account->isWhiteLabel(),
'title' => trans('texts.invoices'),
'entityType' => ENTITY_INVOICE,
'columns' => Utils::trans(['invoice_number', 'invoice_date', 'invoice_total', 'balance_due', 'due_date']),
];
return View::make('public_list', $data);
}
public function getDatatable($clientPublicId = null)
{
$accountId = Auth::user()->account_id;
@ -106,25 +84,6 @@ class InvoiceController extends BaseController
return $this->invoiceRepo->getDatatable($accountId, $clientPublicId, ENTITY_INVOICE, $search);
}
public function getClientDatatable()
{
$search = Input::get('sSearch');
$invitationKey = Session::get('invitation_key');
$invitation = Invitation::where('invitation_key', '=', $invitationKey)->first();
if (!$invitation || $invitation->is_deleted) {
return [];
}
$invoice = $invitation->invoice;
if (!$invoice || $invoice->is_deleted) {
return [];
}
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_INVOICE, $search);
}
public function getRecurringDatatable($clientPublicId = null)
{
$query = $this->invoiceRepo->getRecurringInvoices(Auth::user()->account_id, $clientPublicId, Input::get('sSearch'));

View File

@ -47,28 +47,6 @@ class PaymentController extends BaseController
));
}
public function clientIndex()
{
$invitationKey = Session::get('invitation_key');
if (!$invitationKey) {
app()->abort(404);
}
$invitation = Invitation::with('account')->where('invitation_key', '=', $invitationKey)->first();
$account = $invitation->account;
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [
'color' => $color,
'hideLogo' => $account->isWhiteLabel(),
'entityType' => ENTITY_PAYMENT,
'title' => trans('texts.payments'),
'columns' => Utils::trans(['invoice', 'transaction_reference', 'method', 'payment_amount', 'payment_date'])
];
return View::make('public_list', $data);
}
public function getDatatable($clientPublicId = null)
{
$payments = $this->paymentRepo->find($clientPublicId, Input::get('sSearch'));
@ -114,33 +92,6 @@ class PaymentController extends BaseController
->make();
}
public function getClientDatatable()
{
$search = Input::get('sSearch');
$invitationKey = Session::get('invitation_key');
$invitation = Invitation::where('invitation_key', '=', $invitationKey)->with('contact.client')->first();
if (!$invitation) {
return [];
}
$invoice = $invitation->invoice;
if (!$invoice || $invoice->is_deleted) {
return [];
}
$payments = $this->paymentRepo->findForContact($invitation->contact->id, Input::get('sSearch'));
return Datatable::query($payments)
->addColumn('invoice_number', function ($model) { return $model->invitation_key ? link_to('/view/'.$model->invitation_key, $model->invoice_number) : $model->invoice_number; })
->addColumn('transaction_reference', function ($model) { return $model->transaction_reference ? $model->transaction_reference : '<i>Manual entry</i>'; })
->addColumn('payment_type', function ($model) { return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? '<i>Online payment</i>' : ''); })
->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id); })
->addColumn('payment_date', function ($model) { return Utils::dateToString($model->payment_date); })
->make();
}
public function create($clientPublicId = 0, $invoicePublicId = 0)
{
$invoices = Invoice::scope()

View File

@ -0,0 +1,163 @@
<?php namespace App\Http\Controllers;
use Auth;
use DB;
use Input;
use Utils;
use Datatable;
use App\Models\Invitation;
use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\PaymentRepository;
class PublicClientController extends BaseController
{
private $invoiceRepo;
private $paymentRepo;
public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo)
{
$this->invoiceRepo = $invoiceRepo;
$this->paymentRepo = $paymentRepo;
}
public function dashboard()
{
$invitation = $this->getInvitation();
$account = $invitation->account;
$invoice = $invitation->invoice;
$client = $invoice->client;
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [
'color' => $color,
'account' => $account,
'client' => $client,
];
return response()->view('invited.dashboard', $data);
}
public function activityDatatable()
{
$invitation = $this->getInvitation();
$invoice = $invitation->invoice;
$query = DB::table('activities')
->join('clients', 'clients.id', '=', 'activities.client_id')
->where('activities.client_id', '=', $invoice->client_id)
->where('activities.adjustment', '!=', 0)
->select('activities.id', 'activities.message', 'activities.created_at', 'clients.currency_id', 'activities.balance', 'activities.adjustment');
return Datatable::query($query)
->addColumn('activities.id', function ($model) { return Utils::timestampToDateTimeString(strtotime($model->created_at)); })
->addColumn('message', function ($model) { return strip_tags(Utils::decodeActivity($model->message)); })
->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id); })
->addColumn('adjustment', function ($model) { return $model->adjustment != 0 ? Utils::wrapAdjustment($model->adjustment, $model->currency_id) : ''; })
->make();
}
public function invoiceIndex()
{
$invitation = $this->getInvitation();
$account = $invitation->account;
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [
'color' => $color,
'hideLogo' => $account->isWhiteLabel(),
'title' => trans('texts.invoices'),
'entityType' => ENTITY_INVOICE,
'columns' => Utils::trans(['invoice_number', 'invoice_date', 'invoice_total', 'balance_due', 'due_date']),
];
return response()->view('public_list', $data);
}
public function invoiceDatatable()
{
$invitation = $this->getInvitation();
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_INVOICE, Input::get('sSearch'));
}
public function paymentIndex()
{
$invitation = $this->getInvitation();
$account = $invitation->account;
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [
'color' => $color,
'hideLogo' => $account->isWhiteLabel(),
'entityType' => ENTITY_PAYMENT,
'title' => trans('texts.payments'),
'columns' => Utils::trans(['invoice', 'transaction_reference', 'method', 'payment_amount', 'payment_date'])
];
return response()->view('public_list', $data);
}
public function paymentDatatable()
{
$invitation = $this->getInvitation();
$payments = $this->paymentRepo->findForContact($invitation->contact->id, Input::get('sSearch'));
return Datatable::query($payments)
->addColumn('invoice_number', function ($model) { return $model->invitation_key ? link_to('/view/'.$model->invitation_key, $model->invoice_number) : $model->invoice_number; })
->addColumn('transaction_reference', function ($model) { return $model->transaction_reference ? $model->transaction_reference : '<i>Manual entry</i>'; })
->addColumn('payment_type', function ($model) { return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? '<i>Online payment</i>' : ''); })
->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id); })
->addColumn('payment_date', function ($model) { return Utils::dateToString($model->payment_date); })
->make();
}
public function quoteIndex()
{
$invitation = $this->getInvitation();
$account = $invitation->account;
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [
'color' => $color,
'hideLogo' => $account->isWhiteLabel(),
'title' => trans('texts.quotes'),
'entityType' => ENTITY_QUOTE,
'columns' => Utils::trans(['quote_number', 'quote_date', 'quote_total', 'due_date']),
];
return response()->view('public_list', $data);
}
public function quoteDatatable()
{
$invitation = $this->getInvitation();
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_QUOTE, Input::get('sSearch'));
}
private function getInvitation()
{
$invitationKey = session('invitation_key');
if (!$invitationKey) {
app()->abort(404);
}
$invitation = Invitation::where('invitation_key', '=', $invitationKey)->first();
if (!$invitation || $invitation->is_deleted) {
app()->abort(404);
}
$invoice = $invitation->invoice;
if (!$invoice || $invoice->is_deleted) {
app()->abort(404);
}
return $invitation;
}
}

View File

@ -67,28 +67,6 @@ class QuoteController extends BaseController
return View::make('list', $data);
}
public function clientIndex()
{
$invitationKey = Session::get('invitation_key');
if (!$invitationKey) {
app()->abort(404);
}
$invitation = Invitation::with('account')->where('invitation_key', '=', $invitationKey)->first();
$account = $invitation->account;
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [
'color' => $color,
'hideLogo' => $account->isWhiteLabel(),
'title' => trans('texts.quotes'),
'entityType' => ENTITY_QUOTE,
'columns' => Utils::trans(['quote_number', 'quote_date', 'quote_total', 'due_date']),
];
return View::make('public_list', $data);
}
public function getDatatable($clientPublicId = null)
{
$accountId = Auth::user()->account_id;
@ -97,25 +75,6 @@ class QuoteController extends BaseController
return $this->invoiceRepo->getDatatable($accountId, $clientPublicId, ENTITY_QUOTE, $search);
}
public function getClientDatatable()
{
$search = Input::get('sSearch');
$invitationKey = Session::get('invitation_key');
$invitation = Invitation::where('invitation_key', '=', $invitationKey)->first();
if (!$invitation || $invitation->is_deleted) {
return [];
}
$invoice = $invitation->invoice;
if (!$invoice || $invoice->is_deleted) {
return [];
}
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_QUOTE, $search);
}
public function create($clientPublicId = 0)
{
if (!Utils::isPro()) {

View File

@ -1,36 +0,0 @@
<?php namespace InvoiceNinja\Http\Controllers;
class HomeController extends Controller {
/*
|--------------------------------------------------------------------------
| Home Controller
|--------------------------------------------------------------------------
|
| This controller renders your application's "dashboard" for users that
| are authenticated. Of course, you are free to change or remove the
| controller as you wish. It is just here to get your app started!
|
*/
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard to the user.
*
* @return Response
*/
public function index()
{
return view('home');
}
}

View File

@ -1,36 +0,0 @@
<?php namespace InvoiceNinja\Http\Controllers;
class WelcomeController extends Controller {
/*
|--------------------------------------------------------------------------
| Welcome Controller
|--------------------------------------------------------------------------
|
| This controller renders the "marketing page" for the application and
| is configured to only allow guests. Like most of the other sample
| controllers, you are free to modify or remove it as you desire.
|
*/
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Show the application welcome screen to the user.
*
* @return Response
*/
public function index()
{
return view('welcome');
}
}

View File

@ -48,12 +48,14 @@ Route::get('approve/{invitation_key}', 'QuoteController@approve');
Route::get('payment/{invitation_key}/{payment_type?}', 'PaymentController@show_payment');
Route::post('payment/{invitation_key}', 'PaymentController@do_payment');
Route::get('complete', 'PaymentController@offsite_payment');
Route::get('client/quotes', 'QuoteController@clientIndex');
Route::get('client/invoices', 'InvoiceController@clientIndex');
Route::get('client/payments', 'PaymentController@clientIndex');
Route::get('api/client.quotes', array('as'=>'api.client.quotes', 'uses'=>'QuoteController@getClientDatatable'));
Route::get('api/client.invoices', array('as'=>'api.client.invoices', 'uses'=>'InvoiceController@getClientDatatable'));
Route::get('api/client.payments', array('as'=>'api.client.payments', 'uses'=>'PaymentController@getClientDatatable'));
Route::get('client/quotes', 'PublicClientController@quoteIndex');
Route::get('client/invoices', 'PublicClientController@invoiceIndex');
Route::get('client/payments', 'PublicClientController@paymentIndex');
Route::get('client/dashboard', 'PublicClientController@dashboard');
Route::get('api/client.quotes', array('as'=>'api.client.quotes', 'uses'=>'PublicClientController@quoteDatatable'));
Route::get('api/client.invoices', array('as'=>'api.client.invoices', 'uses'=>'PublicClientController@invoiceDatatable'));
Route::get('api/client.payments', array('as'=>'api.client.payments', 'uses'=>'PublicClientController@paymentDatatable'));
Route::get('api/client.activity', array('as'=>'api.client.activity', 'uses'=>'PublicClientController@activityDatatable'));
Route::get('license', 'PaymentController@show_license_payment');
Route::post('license', 'PaymentController@do_license_payment');

View File

@ -747,4 +747,48 @@ class Utils
$string = str_replace('data:application/pdf;base64,', '', $string);
return base64_decode($string);
}
public static function cityStateZip($city, $state, $postalCode, $swap)
{
$str = $city;
if ($state) {
if ($str) {
$str .= ', ';
}
$str .= $state;
}
if ($swap) {
return $postalCode . ' ' . $str;
} else {
return $str . ' ' . $postalCode;
}
}
public static function formatWebsite($website)
{
if (!$website) {
return '';
}
$link = $website;
$title = $website;
$prefix = 'http://';
if (strlen($link) > 7 && substr($link, 0, 7) === $prefix) {
$title = substr($title, 7);
} else {
$link = $prefix.$link;
}
return link_to($link, $title, array('target' => '_blank'));
}
public static function wrapAdjustment($adjustment, $currencyId)
{
$class = $adjustment <= 0 ? 'success' : 'default';
$adjustment = Utils::formatMoney($adjustment, $currencyId);
return "<h4><div class=\"label label-{$class}\">$adjustment</div></h4>";
}
}

View File

@ -114,6 +114,12 @@ class Account extends Eloquent
return $user->getDisplayName();
}
public function getCityState()
{
$swap = $this->country && $this->country->swap_postal_code;
return Utils::cityStateZip($this->city, $this->state, $this->postal_code, $swap);
}
public function getMomentDateTimeFormat()
{
$format = $this->datetime_format ? $this->datetime_format->format_moment : DEFAULT_DATETIME_MOMENT_FORMAT;
@ -158,12 +164,10 @@ class Account extends Eloquent
return false;
}
/*
public function hasLogo()
{
file_exists($this->getLogoPath());
return file_exists($this->getLogoPath());
}
*/
public function getLogoPath()
{

View File

@ -1,5 +1,6 @@
<?php namespace App\Models;
use Utils;
use DB;
use Illuminate\Database\Eloquent\SoftDeletes;
@ -88,6 +89,12 @@ class Client extends EntityModel
return $contact->getDisplayName();
}
public function getCityState()
{
$swap = $this->country && $this->country->swap_postal_code;
return Utils::cityStateZip($this->city, $this->state, $this->postal_code, $swap);
}
public function getEntityType()
{
return ENTITY_CLIENT;
@ -113,25 +120,6 @@ class Client extends EntityModel
return false;
}
public function getWebsite()
{
if (!$this->website) {
return '';
}
$link = $this->website;
$title = $this->website;
$prefix = 'http://';
if (strlen($link) > 7 && substr($link, 0, 7) === $prefix) {
$title = substr($title, 7);
} else {
$link = $prefix.$link;
}
return link_to($link, $title, array('target' => '_blank'));
}
public function getDateCreated()
{
if ($this->created_at == '0000-00-00 00:00:00') {

File diff suppressed because one or more lines are too long

View File

@ -779,4 +779,181 @@ div.DTFC_LeftBodyWrapper tbody tr:first-child td {
div.DTFC_LeftFootWrapper table {
border-top: none;
}
}
body {
font-family: 'Roboto', sans-serif;
font-size: 14px;
background-color: #f8f8f8;
}
@media screen and (min-width: 700px) {
.navbar-header {
padding-top: 16px;
padding-bottom: 16px;
}
.navbar li a {
padding: 31px 20px 31px 20px;
}
}
#footer {
text-align: center
}
#footer .top {
background: #2e2b2b;
font-size: 12px;
font-weight: 900;
text-transform: uppercase;
padding: 40px 0 27px;
}
#footer .top li {
display: inline-block;
margin: 0 30px 10px;
}
#footer .top a {
color: #fff;
text-decoration: none;
}
#footer .bottom {
border-top: 1px solid #5f5d5d;
background: #211f1f;
font-size: 11px;
font-weight: 400;
color: #636262;
padding: 28px 0;
}
#footer .bottom a {
color: #636262;
}
#footer .menu-item-31 a:before {
content: '';
display: inline-block;
width: 9px;
height: 15px;
background: url({{ asset('images/social/facebook.svg') }}) no-repeat;
margin: 0 6px 0 0;
position: relative;
top: 3px;
}
#footer .menu-item-32 a:before {
content: '';
display: inline-block;
width: 19px;
height: 16px;
background: url({{ asset('images/social/twitter.svg') }}) no-repeat;
margin: 0 6px 0 0;
position: relative;
top: 3px;
}
#footer .menu-item-33 a:before {
content: '';
display: inline-block;
width: 19px;
height: 16px;
background: url({{ asset('images/social/github.png') }}) no-repeat;
margin: 0 6px 0 0;
position: relative;
top: 3px;
}
/* Hide bootstrap sort header icons */
table.data-table thead .sorting:after { content: '' !important }
table.data-table thead .sorting_asc:after { content: '' !important }
table.data-table thead .sorting_desc:after { content: '' !important}
table.data-table thead .sorting_asc_disabled:after { content: '' !important }
table.data-table thead .sorting_desc_disabled:after { content: '' !important }
.dataTables_length {
padding-left: 20px;
padding-top: 8px;
}
.dataTables_length label {
font-weight: 500;
}
@media screen and (min-width: 700px) {
#footer .top {
padding: 27px 0;
}
#footer .bottom {
padding: 25px 0;
}
}
table.dataTable { border-radius: 3px; border-collapse: collapse;
/*border-spacing: 0;*/}
table.dataTable thead > tr > th, table.invoice-table thead > tr > th {
color:#fff;
}
th:first-child {
border-radius: 3px 0 0 0;
border-left: none;
}
th:last-child {
border-radius: 0 3px 0 0;
}
tr {border: none;}
td {
padding-top: 16px !important;
padding-bottom: 16px !important;
}
/*th {border-left: 1px solid #d26b26; }*/
th {border-left: 1px solid #FFFFFF; }
.table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td {
vertical-align: middle;
border-top: none;
border-bottom: 1px solid #dfe0e1;
}
table.dataTable.no-footer {
border-bottom: none;
}
.table-striped>tbody>tr:nth-child(odd)>td,
.table-striped>tbody>tr:nth-child(odd)>th {
background-color: #FDFDFD;
}
table.table thead .sorting_asc {
background: url('../images/sort_asc.png') no-repeat 90% 50%;
}
table.table thead .sorting_desc {
background: url('../images/sort_desc.png') no-repeat 90% 50%;
}
table.dataTable thead th, table.dataTable thead td, table.invoice-table thead th, table.invoice-table thead td {
padding: 12px 10px;
}
table.dataTable tbody th, table.dataTable tbody td {
padding: 10px;
}
.dataTables_wrapper {
padding-top: 16px;
}
table.table thead > tr > th {
border-bottom-width: 0px;
}
table td {
max-width: 250px;
}
.pagination>li:first-child>a, .pagination>li:first-child>span {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
/* hide table sorting indicators */
table.data-table thead .sorting { background: url('') no-repeat center right; }

177
public/css/public.style.css vendored Normal file
View File

@ -0,0 +1,177 @@
body {
font-family: 'Roboto', sans-serif;
font-size: 14px;
background-color: #f8f8f8;
}
@media screen and (min-width: 700px) {
.navbar-header {
padding-top: 16px;
padding-bottom: 16px;
}
.navbar li a {
padding: 31px 20px 31px 20px;
}
}
#footer {
text-align: center
}
#footer .top {
background: #2e2b2b;
font-size: 12px;
font-weight: 900;
text-transform: uppercase;
padding: 40px 0 27px;
}
#footer .top li {
display: inline-block;
margin: 0 30px 10px;
}
#footer .top a {
color: #fff;
text-decoration: none;
}
#footer .bottom {
border-top: 1px solid #5f5d5d;
background: #211f1f;
font-size: 11px;
font-weight: 400;
color: #636262;
padding: 28px 0;
}
#footer .bottom a {
color: #636262;
}
#footer .menu-item-31 a:before {
content: '';
display: inline-block;
width: 9px;
height: 15px;
background: url({{ asset('images/social/facebook.svg') }}) no-repeat;
margin: 0 6px 0 0;
position: relative;
top: 3px;
}
#footer .menu-item-32 a:before {
content: '';
display: inline-block;
width: 19px;
height: 16px;
background: url({{ asset('images/social/twitter.svg') }}) no-repeat;
margin: 0 6px 0 0;
position: relative;
top: 3px;
}
#footer .menu-item-33 a:before {
content: '';
display: inline-block;
width: 19px;
height: 16px;
background: url({{ asset('images/social/github.png') }}) no-repeat;
margin: 0 6px 0 0;
position: relative;
top: 3px;
}
/* Hide bootstrap sort header icons */
table.table thead .sorting:after { content: '' !important }
table.table thead .sorting_asc:after { content: '' !important }
table.table thead .sorting_desc:after { content: '' !important }
table.table thead .sorting_asc_disabled:after { content: '' !important }
table.table thead .sorting_desc_disabled:after { content: '' !important }
.dataTables_length {
padding-left: 20px;
padding-top: 8px;
}
.dataTables_length label {
font-weight: 500;
}
@media screen and (min-width: 700px) {
#footer .top {
padding: 27px 0;
}
#footer .bottom {
padding: 25px 0;
}
}
table.dataTable { border-radius: 3px; border-collapse: collapse;
/*border-spacing: 0;*/}
table.dataTable thead > tr > th, table.invoice-table thead > tr > th {
color:#fff;
}
th:first-child {
border-radius: 3px 0 0 0;
border-left: none;
}
th:last-child {
border-radius: 0 3px 0 0;
}
tr {border: none;}
td {
padding-top: 16px !important;
padding-bottom: 16px !important;
}
/*th {border-left: 1px solid #d26b26; }*/
th {border-left: 1px solid #FFFFFF; }
.table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td {
vertical-align: middle;
border-top: none;
border-bottom: 1px solid #dfe0e1;
}
table.dataTable.no-footer {
border-bottom: none;
}
.table-striped>tbody>tr:nth-child(odd)>td,
.table-striped>tbody>tr:nth-child(odd)>th {
background-color: #FDFDFD;
}
table.table thead .sorting_asc {
background: url('../images/sort_asc.png') no-repeat 90% 50%;
}
table.table thead .sorting_desc {
background: url('../images/sort_desc.png') no-repeat 90% 50%;
}
table.dataTable thead th, table.dataTable thead td, table.invoice-table thead th, table.invoice-table thead td {
padding: 12px 10px;
}
table.dataTable tbody th, table.dataTable tbody td {
padding: 10px;
}
.dataTables_wrapper {
padding-top: 16px;
}
table.table thead > tr > th {
border-bottom-width: 0px;
}
table td {
max-width: 250px;
}
.pagination>li:first-child>a, .pagination>li:first-child>span {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
/* hide table sorting indicators */
table.data-table thead .sorting { background: url('') no-repeat center right; }

1378
public/css/splash.css vendored

File diff suppressed because it is too large Load Diff

View File

@ -815,5 +815,9 @@
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -814,5 +814,9 @@ return array(
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -815,6 +815,8 @@ return array(
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -792,5 +792,9 @@ return array(
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -814,5 +814,9 @@ return array(
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -806,5 +806,9 @@ return array(
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -807,5 +807,9 @@ return array(
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -808,5 +808,9 @@ return array(
'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice',
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -815,6 +815,10 @@ return array(
'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice',
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -814,4 +814,8 @@ return array(
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -808,5 +808,9 @@ return array(
'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice',
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -808,5 +808,9 @@ return array(
'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice',
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -811,5 +811,9 @@ return array(
'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice',
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance',
);

View File

@ -42,7 +42,7 @@
{!! Former::text('work_phone') !!}
{!! Former::file('logo')->max(2, 'MB')->accept('image')->inlineHelp(trans('texts.logo_help')) !!}
@if (file_exists($account->getLogoPath()))
@if ($account->hasLogo())
<center>
{!! HTML::image($account->getLogoPath().'?no_cache='.time(), 'Logo', ['width' => 200]) !!} &nbsp;
<a href="#" onclick="deleteLogo()">{{ trans('texts.remove_logo') }}</a>

View File

@ -78,14 +78,8 @@
@if ($client->address2)
{{ $client->address2 }}<br/>
@endif
@if ($client->city)
{{ $client->city }},
@endif
@if ($client->state)
{{ $client->state }}
@endif
@if ($client->postal_code)
{{ $client->postal_code }}
@if ($client->getCityState())
{{ $client->getCityState() }}<br/>
@endif
@if ($client->country)
<br/>{{ $client->country->name }}
@ -114,7 +108,7 @@
@endif
@if ($client->website)
<p>{!! $client->getWebsite() !!}</p>
<p>{!! Utils::formatWebsite($client->website) !!}</p>
@endif
@if ($client->language)

View File

@ -0,0 +1,170 @@
@extends('public.header')
@section('head')
@parent
<style type="text/css">
body {
line-height: 1.5em;
}
div.main-container {
min-height: 700px;
}
div.row {
padding-top: 2em;
padding-bottom: 2em;
}
div.logo img {
max-width:300px;
max-height:200px;
}
div.address-details {
color: #666666;
}
div.col-md-4-left {
padding-left: 15px;
padding-right: 6px;
}
div.col-md-4-center {
padding-left: 6px;
padding-right: 6px;
}
div.col-md-4-right {
padding-left: 6px;
padding-right: 15px;
}
div.well {
background-color: white;
color: #0b4d78;
text-transform: uppercase;
text-align: center;
font-weight: 600;
padding-top: 40px;
padding-bottom: 40px;
}
div.well .fa {
color: green;
font-size: 18px;
margin-bottom: 6px;
}
div.well .amount {
margin-top: 10px;
font-size: 32px;
font-weight: 300;
color: black;
}
table.dataTable thead > tr > th, table.invoice-table thead > tr > th {
background-color: {{ $color }} !important;
}
.pagination>.active>a,
.pagination>.active>span,
.pagination>.active>a:hover,
.pagination>.active>span:hover,
.pagination>.active>a:focus,
.pagination>.active>span:focus {
background-color: {{ $color }};
border-color: {{ $color }};
}
table.table thead .sorting:after { content: '' !important }
table.table thead .sorting_asc:after { content: '' !important }
table.table thead .sorting_desc:after { content: '' !important }
table.table thead .sorting_asc_disabled:after { content: '' !important }
table.table thead .sorting_desc_disabled:after { content: '' !important }
</style>
@stop
@section('content')
<div class="container main-container">
<div class="row">
<div class="col-md-3 logo">
@if ($account->hasLogo())
{!! HTML::image($account->getLogoPath()) !!}
@endif
</div>
<div class="col-md-3 col-md-offset-3 address-details">
@if ($account->address1)
{{ $account->address1 }}<br/>
@endif
@if ($account->address2)
{{ $account->address2 }}<br/>
@endif
@if ($account->getCityState())
{{ $account->getCityState() }}<br/>
@endif
</div>
<div class="col-md-3 address-details">
@if ($account->work_phone)
<i class="fa fa-phone" style="width: 20px"></i>{{ $account->work_phone }}<br/>
@endif
@if ($account->work_email)
<i class="fa fa-envelope" style="width: 20px"></i>{!! HTML::mailto($account->work_email, $account->work_email) !!}<br/>
@endif
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-4-left">
<div class="well">
<div class="fa fa-file-text-o"></div>
<div>
{{ trans('texts.total_invoiced') }}
</div>
<div class="amount">
{{ Utils::formatMoney($client->paid_to_date + $client->balance, $client->currency_id ?: $account->currency_id) }}
</div>
</div>
</div>
<div class="col-md-4 col-md-4-center">
<div class="well">
<div class="fa fa-credit-card"></div>
<div>
{{ trans('texts.paid_to_date') }}
</div>
<div class="amount">
{{ Utils::formatMoney($client->paid_to_date, $client->currency_id ?: $account->currency_id) }}
</div>
</div>
</div>
<div class="col-md-4 col-md-4-right">
<div class="well">
<div class="fa fa-server"></div>
<div>
{{ trans('texts.open_balance') }}
</div>
<div class="amount">
{{ Utils::formatMoney($client->balance, $client->currency_id ?: $account->currency_id) }}
</div>
</div>
</div>
</div>
{!! Datatable::table()
->addColumn(
trans('texts.date'),
trans('texts.message'),
trans('texts.balance'),
trans('texts.adjustment'))
->setUrl(route('api.client.activity'))
->setOptions('bFilter', false)
->setOptions('aaSorting', [['0', 'desc']])
->setOptions('sPaginationType', 'bootstrap')
->render('datatable') !!}
</div>
@stop

View File

@ -1,123 +1,7 @@
@extends('master')
@section('head')
<link href="{{ asset('css/built.public.css') }}?no_cache={{ NINJA_VERSION }}" rel="stylesheet" type="text/css"/>
<style type="text/css">
body {
font-family: 'Roboto', sans-serif;
font-size: 14px;
}
@media screen and (min-width: 700px) {
.navbar-header {
padding-top: 16px;
padding-bottom: 16px;
}
.navbar li a {
padding: 31px 20px 31px 20px;
}
}
#footer {
text-align: center
}
#footer .top {
background: #2e2b2b;
font-size: 12px;
font-weight: 900;
text-transform: uppercase;
padding: 40px 0 27px;
}
#footer .top li {
display: inline-block;
margin: 0 30px 10px;
}
#footer .top a {
color: #fff;
text-decoration: none;
}
#footer .bottom {
border-top: 1px solid #5f5d5d;
background: #211f1f;
font-size: 11px;
font-weight: 400;
color: #636262;
padding: 28px 0;
}
#footer .bottom a {
color: #636262;
}
#footer .menu-item-31 a:before {
content: '';
display: inline-block;
width: 9px;
height: 15px;
background: url({{ asset('images/social/facebook.svg') }}) no-repeat;
margin: 0 6px 0 0;
position: relative;
top: 3px;
}
#footer .menu-item-32 a:before {
content: '';
display: inline-block;
width: 19px;
height: 16px;
background: url({{ asset('images/social/twitter.svg') }}) no-repeat;
margin: 0 6px 0 0;
position: relative;
top: 3px;
}
#footer .menu-item-33 a:before {
content: '';
display: inline-block;
width: 19px;
height: 16px;
background: url({{ asset('images/social/github.png') }}) no-repeat;
margin: 0 6px 0 0;
position: relative;
top: 3px;
}
/* Hide bootstrap sort header icons */
table.table thead .sorting:after { content: '' !important }
table.table thead .sorting_asc:after { content: '' !important }
table.table thead .sorting_desc:after { content: '' !important}
table.table thead .sorting_asc_disabled:after { content: '' !important }
table.table thead .sorting_desc_disabled:after { content: '' !important }
.dataTables_length {
padding-left: 20px;
padding-top: 8px;
}
.dataTables_length label {
font-weight: 500;
}
@media screen and (min-width: 700px) {
#footer .top {
padding: 27px 0;
}
#footer .bottom {
padding: 25px 0;
}
}
</style>
<link href="{{ asset('css/built.public.css') }}?no_cache={{ NINJA_VERSION }}" rel="stylesheet" type="text/css"/>
@stop
@section('body')
@ -184,6 +68,9 @@ table.table thead .sorting_desc_disabled:after { content: '' !important }
<div id="navbar" class="collapse navbar-collapse">
@if (!isset($hideHeader) || !$hideHeader)
<ul class="nav navbar-nav navbar-right">
<li {{ Request::is('*client/dashboard') ? 'class="active"' : '' }}>
{!! link_to('/client/dashboard', trans('texts.dashboard') ) !!}
</li>
<li {{ Request::is('*client/quotes') ? 'class="active"' : '' }}>
{!! link_to('/client/quotes', trans('texts.quotes') ) !!}
</li>

View File

@ -3,80 +3,25 @@
@section('content')
<style type="text/css">
table.dataTable thead > tr > th, table.invoice-table thead > tr > th {
background-color: {{ $color }} !important;
}
body {
background-color: #f8f8f8;
}
.pagination>.active>a,
.pagination>.active>span,
.pagination>.active>a:hover,
.pagination>.active>span:hover,
.pagination>.active>a:focus,
.pagination>.active>span:focus {
background-color: {{ $color }};
border-color: {{ $color }};
}
table.dataTable { border-radius: 3px; border-collapse: collapse;
/*border-spacing: 0;*/}
table.dataTable thead > tr > th, table.invoice-table thead > tr > th {
background-color: {{ $color }} !important;
color:#fff;
}
th:first-child {
border-radius: 3px 0 0 0;
border-left: none;
}
th:last-child {
border-radius: 0 3px 0 0;
}
tr {border: none;}
td {
padding-top: 16px !important;
padding-bottom: 16px !important;
}
/*th {border-left: 1px solid #d26b26; }*/
th {border-left: 1px solid #FFFFFF; }
.table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td {
vertical-align: middle;
border-top: none;
border-bottom: 1px solid #dfe0e1;
}
table.dataTable.no-footer {
border-bottom: none;
}
.table-striped>tbody>tr:nth-child(odd)>td,
.table-striped>tbody>tr:nth-child(odd)>th {
background-color: #FDFDFD;
}
table.table thead .sorting_asc {
background: url('../images/sort_asc.png') no-repeat 90% 50%;
}
table.table thead .sorting_desc {
background: url('../images/sort_desc.png') no-repeat 90% 50%;
}
table.dataTable thead th, table.dataTable thead td, table.invoice-table thead th, table.invoice-table thead td {
padding: 12px 10px;
}
table.dataTable tbody th, table.dataTable tbody td {
padding: 10px;
}
.dataTables_wrapper {
padding-top: 16px;
}
table.table thead > tr > th {
border-bottom-width: 0px;
}
table td {
max-width: 250px;
}
.pagination>.active>a, .pagination>.active>span, .pagination>.active>a:hover, .pagination>.active>span:hover, .pagination>.active>a:focus, .pagination>.active>span:focus {
background-color: {{ $color }};
border-color: {{ $color }};
}
.pagination>li:first-child>a, .pagination>li:first-child>span {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
/* hide table sorting indicators */
table.table thead .sorting { background: url('') no-repeat center right; }
table.table thead .sorting:after { content: '' !important }
table.table thead .sorting_asc:after { content: '' !important }
table.table thead .sorting_desc:after { content: '' !important }
table.table thead .sorting_asc_disabled:after { content: '' !important }
table.table thead .sorting_desc_disabled:after { content: '' !important }
</style>
@ -86,7 +31,7 @@
<!--
<div id="top_right_buttons" class="pull-right">
<input id="tableFilter" type="text" style="width:140px;margin-right:17px" class="form-control pull-left" placeholder="{{ trans('texts.filter') }}"/>
<input id="tableFilter" type="text" style="width:140px;margin-right:17px" class="form-control pull-left" placeholder="{{ trans('texts.filter') }}"/>
</div>
-->