mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Working on history sidebar
This commit is contained in:
parent
a2f7d32e57
commit
db0c305b4f
@ -89,9 +89,7 @@ class ClientController extends BaseController
|
|||||||
public function show(ClientRequest $request)
|
public function show(ClientRequest $request)
|
||||||
{
|
{
|
||||||
$client = $request->entity();
|
$client = $request->entity();
|
||||||
|
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT);
|
|
||||||
|
|
||||||
$actionLinks = [];
|
$actionLinks = [];
|
||||||
if($user->can('create', ENTITY_TASK)){
|
if($user->can('create', ENTITY_TASK)){
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use Input;
|
use Input;
|
||||||
use Utils;
|
use Utils;
|
||||||
|
use App\Libraries\HistoryUtils;
|
||||||
|
|
||||||
class EntityRequest extends Request {
|
class EntityRequest extends Request {
|
||||||
|
|
||||||
@ -52,7 +53,10 @@ class EntityRequest extends Request {
|
|||||||
public function authorize()
|
public function authorize()
|
||||||
{
|
{
|
||||||
if ($this->entity()) {
|
if ($this->entity()) {
|
||||||
return $this->user()->can('view', $this->entity());
|
if ($this->user()->can('view', $this->entity())) {
|
||||||
|
HistoryUtils::trackViewed($this->entity());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return $this->user()->can('create', $this->entityType);
|
return $this->user()->can('create', $this->entityType);
|
||||||
}
|
}
|
||||||
@ -62,4 +66,5 @@ class EntityRequest extends Request {
|
|||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('ENV_DEVELOPMENT', 'local');
|
define('ENV_DEVELOPMENT', 'local');
|
||||||
define('ENV_STAGING', 'staging');
|
define('ENV_STAGING', 'staging');
|
||||||
|
|
||||||
define('RECENTLY_VIEWED', 'RECENTLY_VIEWED');
|
define('RECENTLY_VIEWED', 'recent_history');
|
||||||
|
|
||||||
define('ENTITY_CLIENT', 'client');
|
define('ENTITY_CLIENT', 'client');
|
||||||
define('ENTITY_CONTACT', 'contact');
|
define('ENTITY_CONTACT', 'contact');
|
||||||
|
117
app/Libraries/HistoryUtils.php
Normal file
117
app/Libraries/HistoryUtils.php
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<?php namespace App\Libraries;
|
||||||
|
|
||||||
|
use Request;
|
||||||
|
use stdClass;
|
||||||
|
use Session;
|
||||||
|
use App\Models\EntityModel;
|
||||||
|
|
||||||
|
class HistoryUtils
|
||||||
|
{
|
||||||
|
public static function trackViewed(EntityModel $entity)
|
||||||
|
{
|
||||||
|
if ($entity->isEntityType(ENTITY_CREDIT) || $entity->isEntityType(ENTITY_VENDOR)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$object = static::convertToObject($entity);
|
||||||
|
$history = Session::get(RECENTLY_VIEWED);
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
// Add to the list and make sure to only show each item once
|
||||||
|
for ($i = 0; $i<count($history); $i++) {
|
||||||
|
$item = $history[$i];
|
||||||
|
|
||||||
|
if ($object->url == $item->url) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_push($data, $item);
|
||||||
|
|
||||||
|
if (isset($counts[$item->accountId])) {
|
||||||
|
$counts[$item->accountId]++;
|
||||||
|
} else {
|
||||||
|
$counts[$item->accountId] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
array_unshift($data, $object);
|
||||||
|
|
||||||
|
if (isset($counts[$entity->account_id]) && $counts[$entity->account_id] > RECENTLY_VIEWED_LIMIT) {
|
||||||
|
array_pop($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//$data = [];
|
||||||
|
Session::put(RECENTLY_VIEWED, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function convertToObject($entity)
|
||||||
|
{
|
||||||
|
$object = new stdClass();
|
||||||
|
$object->accountId = $entity->account_id;
|
||||||
|
$object->url = $entity->present()->url;
|
||||||
|
$object->entityType = $entity->subEntityType();
|
||||||
|
$object->name = $entity->present()->titledName;
|
||||||
|
$object->timestamp = time();
|
||||||
|
|
||||||
|
if ($entity->isEntityType(ENTITY_CLIENT)) {
|
||||||
|
$object->client_id = $entity->public_id;
|
||||||
|
$object->client_name = $entity->getDisplayName();
|
||||||
|
} elseif (method_exists($entity, 'client') && $entity->client) {
|
||||||
|
$object->client_id = $entity->client->public_id;
|
||||||
|
$object->client_name = $entity->client->getDisplayName();
|
||||||
|
} else {
|
||||||
|
$object->client_id = 0;
|
||||||
|
$object->client_name = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function renderHtml()
|
||||||
|
{
|
||||||
|
$lastClientId = false;
|
||||||
|
$clientMap = [];
|
||||||
|
$str = '';
|
||||||
|
|
||||||
|
foreach (Session::get(RECENTLY_VIEWED) as $item)
|
||||||
|
{
|
||||||
|
if ($item->entityType == ENTITY_CLIENT && isset($clientMap[$item->client_id])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$clientMap[$item->client_id] = true;
|
||||||
|
|
||||||
|
if ($lastClientId === false || $item->client_id != $lastClientId)
|
||||||
|
{
|
||||||
|
$icon = '<i class="fa fa-users" style="width:30px"></i>';
|
||||||
|
if ($item->client_id) {
|
||||||
|
$link = url('/clients/' . $item->client_id);
|
||||||
|
$name = $item->client_name ;
|
||||||
|
|
||||||
|
$buttonLink = url('/invoices/create/' . $item->client_id);
|
||||||
|
$button = '<a type="button" class="btn btn-primary btn-sm pull-right" style="margin-top:5px; margin-right:10px; text-indent:0px"
|
||||||
|
href="' . $buttonLink . '">
|
||||||
|
<i class="fa fa-plus-circle" style="width:20px" title="' . trans('texts.create_new') . '"></i>
|
||||||
|
</a>';
|
||||||
|
} else {
|
||||||
|
$link = '#';
|
||||||
|
$name = trans('texts.unassigned');
|
||||||
|
$button = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$str .= sprintf('<li>%s<a href="%s"><div>%s %s</div></a></li>', $button, $link, $icon, $name);
|
||||||
|
$lastClientId = $item->client_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($item->entityType == ENTITY_CLIENT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$icon = '<i class="fa fa-' . EntityModel::getIcon($item->entityType . 's') . '"></i>';
|
||||||
|
$str .= sprintf('<li style="text-align:right; padding-right:20px;"><a href="%s">%s %s</a></li>', $item->url, $item->name, $icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
//dd($str);
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
}
|
@ -602,6 +602,7 @@ class Utils
|
|||||||
|
|
||||||
public static function trackViewed($name, $type, $url = false)
|
public static function trackViewed($name, $type, $url = false)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
if (!$url) {
|
if (!$url) {
|
||||||
$url = Request::url();
|
$url = Request::url();
|
||||||
}
|
}
|
||||||
@ -643,6 +644,7 @@ class Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
Session::put(RECENTLY_VIEWED, $data);
|
Session::put(RECENTLY_VIEWED, $data);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function processVariables($str)
|
public static function processVariables($str)
|
||||||
|
@ -92,6 +92,16 @@ class EntityModel extends Eloquent
|
|||||||
return $this->public_id . ':' . $this->getEntityType();
|
return $this->public_id . ':' . $this->getEntityType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function subEntityType()
|
||||||
|
{
|
||||||
|
return $this->getEntityType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEntityType($type)
|
||||||
|
{
|
||||||
|
return $this->getEntityType() === $type;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public function getEntityType()
|
public function getEntityType()
|
||||||
{
|
{
|
||||||
@ -229,4 +239,23 @@ class EntityModel extends Eloquent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getIcon($entityType)
|
||||||
|
{
|
||||||
|
$icons = [
|
||||||
|
'dashboard' => 'tachometer',
|
||||||
|
'clients' => 'users',
|
||||||
|
'invoices' => 'file-pdf-o',
|
||||||
|
'payments' => 'credit-card',
|
||||||
|
'recurring_invoices' => 'files-o',
|
||||||
|
'credits' => 'credit-card',
|
||||||
|
'quotes' => 'file-text-o',
|
||||||
|
'tasks' => 'clock-o',
|
||||||
|
'expenses' => 'file-image-o',
|
||||||
|
'vendors' => 'building',
|
||||||
|
'settings' => 'cog',
|
||||||
|
];
|
||||||
|
|
||||||
|
return array_get($icons, $entityType);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -107,10 +107,7 @@ class Expense extends EntityModel
|
|||||||
*/
|
*/
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
if($this->expense_number)
|
return $this->transaction_id ?: '#' . $this->public_id;
|
||||||
return $this->expense_number;
|
|
||||||
|
|
||||||
return $this->public_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -548,6 +548,15 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
return $this->isType(INVOICE_TYPE_QUOTE) ? ENTITY_QUOTE : ENTITY_INVOICE;
|
return $this->isType(INVOICE_TYPE_QUOTE) ? ENTITY_QUOTE : ENTITY_INVOICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function subEntityType()
|
||||||
|
{
|
||||||
|
if ($this->is_recurring) {
|
||||||
|
return ENTITY_RECURRING_INVOICE;
|
||||||
|
} else {
|
||||||
|
return $this->getEntityType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
|
@ -151,9 +151,15 @@ class Task extends EntityModel
|
|||||||
{
|
{
|
||||||
return "/tasks/{$this->public_id}/edit";
|
return "/tasks/{$this->public_id}/edit";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return '#' . $this->public_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Task::created(function ($task) {
|
Task::created(function ($task) {
|
||||||
event(new TaskWasCreated($task));
|
event(new TaskWasCreated($task));
|
||||||
});
|
});
|
||||||
|
@ -27,4 +27,12 @@ class EntityPresenter extends Presenter
|
|||||||
|
|
||||||
return link_to($link, $name)->toHtml();
|
return link_to($link, $name)->toHtml();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function titledName()
|
||||||
|
{
|
||||||
|
$entity = $this->entity;
|
||||||
|
$entityType = $entity->getEntityType();
|
||||||
|
|
||||||
|
return sprintf('%s: %s', trans('texts.' . $entityType), $entity->getDisplayName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ class EventServiceProvider extends ServiceProvider {
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $listen = [
|
protected $listen = [
|
||||||
|
|
||||||
// Clients
|
// Clients
|
||||||
'App\Events\ClientWasCreated' => [
|
'App\Events\ClientWasCreated' => [
|
||||||
'App\Listeners\ActivityListener@createdClient',
|
'App\Listeners\ActivityListener@createdClient',
|
||||||
|
@ -2089,6 +2089,8 @@ $LANG = array(
|
|||||||
|
|
||||||
'toggle_navigation' => 'Toggle Navigation',
|
'toggle_navigation' => 'Toggle Navigation',
|
||||||
'toggle_history' => 'Toggle History',
|
'toggle_history' => 'Toggle History',
|
||||||
|
'unassigned' => 'Unassigned',
|
||||||
|
'task' => 'Task',
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -64,7 +64,6 @@
|
|||||||
#right-sidebar-wrapper {
|
#right-sidebar-wrapper {
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0px;
|
|
||||||
right: 250px;
|
right: 250px;
|
||||||
width: 0px;
|
width: 0px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -104,20 +103,34 @@
|
|||||||
/* Sidebar Styles */
|
/* Sidebar Styles */
|
||||||
|
|
||||||
.sidebar-nav {
|
.sidebar-nav {
|
||||||
|
padding-top: 16px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 250px;
|
width: 250px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
list-style: none;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-nav i.fa {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-nav li {
|
.sidebar-nav li {
|
||||||
|
border-bottom:solid 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#left-sidebar-wrapper .sidebar-nav li {
|
||||||
text-indent: 20px;
|
text-indent: 20px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#right-sidebar-wrapper .sidebar-nav li {
|
||||||
|
text-indent: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-nav li > a {
|
.sidebar-nav li > a {
|
||||||
display: block;
|
display: block;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
@ -163,6 +176,17 @@
|
|||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-nav li div {
|
||||||
|
max-width:226px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-nav li:hover div {
|
||||||
|
max-width:186px;
|
||||||
|
}
|
||||||
|
|
||||||
@media(min-width:768px) {
|
@media(min-width:768px) {
|
||||||
#wrapper {
|
#wrapper {
|
||||||
padding-left: 250px;
|
padding-left: 250px;
|
||||||
@ -700,33 +724,33 @@
|
|||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div id="left-sidebar-wrapper">
|
<div id="left-sidebar-wrapper">
|
||||||
<ul class="sidebar-nav" style="padding-top:20px">
|
<ul class="sidebar-nav">
|
||||||
@foreach([
|
@foreach([
|
||||||
'dashboard' => 'tachometer',
|
'dashboard',
|
||||||
'clients' => 'users',
|
'clients',
|
||||||
'invoices' => 'file-pdf-o',
|
'invoices',
|
||||||
'payments' => 'credit-card',
|
'payments',
|
||||||
'recurring_invoices' => 'files-o',
|
'recurring_invoices',
|
||||||
'credits' => 'credit-card',
|
'credits',
|
||||||
'quotes' => 'file-text-o',
|
'quotes',
|
||||||
'tasks' => 'clock-o',
|
'tasks',
|
||||||
'expenses' => 'file-image-o',
|
'expenses',
|
||||||
'vendors' => 'building',
|
'vendors',
|
||||||
'settings' => 'cog',
|
'settings'
|
||||||
] as $option => $icon)
|
] as $option)
|
||||||
<li style="border-bottom:solid 1px" class="{{ Request::is("{$option}*") ? 'active' : '' }}">
|
<li class="{{ Request::is("{$option}*") ? 'active' : '' }}">
|
||||||
@if ($option != 'dashboard' && $option != 'settings')
|
@if ($option != 'dashboard' && $option != 'settings')
|
||||||
@if (Auth::user()->can('create', substr($option, 0, -1)))
|
@if (Auth::user()->can('create', substr($option, 0, -1)))
|
||||||
<a type="button" class="btn btn-primary btn-sm pull-right" style="margin-top:10px;margin-right:10px;text-indent:0px"
|
<a type="button" class="btn btn-primary btn-sm pull-right" style="margin-top:10px;margin-right:10px;text-indent:0px"
|
||||||
href="{{ url("/{$option}/create") }}">
|
href="{{ url("/{$option}/create") }}">
|
||||||
<i class="fa fa-plus-circle" style="color:white;width:20px" title="{{ trans('texts.create_new') }}"></i>
|
<i class="fa fa-plus-circle" style="width:20px" title="{{ trans('texts.create_new') }}"></i>
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
<a href="{{ url($option == 'recurring' ? 'recurring_invoice' : $option) }}"
|
<a href="{{ url($option == 'recurring' ? 'recurring_invoice' : $option) }}"
|
||||||
style="font-size:16px; padding-top:6px; padding-bottom:6px"
|
style="font-size:16px; padding-top:6px; padding-bottom:6px"
|
||||||
class="{{ Request::is("{$option}*") ? 'active' : '' }}">
|
class="{{ Request::is("{$option}*") ? 'active' : '' }}">
|
||||||
<i class="fa fa-{{ $icon }}" style="width:46px; color:white; padding-right:10px"></i>
|
<i class="fa fa-{{ \App\Models\EntityModel::getIcon($option) }}" style="width:46px; padding-right:10px"></i>
|
||||||
{{ ($option == 'recurring_invoices') ? trans('texts.recurring') : trans("texts.{$option}") }}
|
{{ ($option == 'recurring_invoices') ? trans('texts.recurring') : trans("texts.{$option}") }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@ -736,7 +760,9 @@
|
|||||||
<!-- /#left-sidebar-wrapper -->
|
<!-- /#left-sidebar-wrapper -->
|
||||||
|
|
||||||
<div id="right-sidebar-wrapper">
|
<div id="right-sidebar-wrapper">
|
||||||
SIDEBAR
|
<ul class="sidebar-nav">
|
||||||
|
{!! \App\Libraries\HistoryUtils::renderHtml() !!}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Page Content -->
|
<!-- Page Content -->
|
||||||
|
Loading…
x
Reference in New Issue
Block a user