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

Working on history sidebar

This commit is contained in:
Hillel Coren 2016-09-01 18:52:26 +03:00
parent 69e54e72ca
commit e535750127
15 changed files with 389 additions and 314 deletions

View File

@ -139,8 +139,6 @@ class AccountController extends BaseController
$account = $this->accountRepo->create();
$user = $account->users()->first();
Session::forget(RECENTLY_VIEWED);
if ($prevUserId) {
$users = $this->accountRepo->associateAccounts($user->id, $prevUserId);
Session::put(SESSION_USER_ACCOUNTS, $users);

View File

@ -115,7 +115,6 @@ class InvoiceController extends BaseController
$method = 'POST';
$url = "{$entityType}s";
} else {
Utils::trackViewed($invoice->getDisplayName().' - '.$invoice->client->getDisplayName(), $invoice->getEntityType());
$method = 'PUT';
$url = "{$entityType}s/{$invoice->public_id}";
$clients->whereId($invoice->client_id);
@ -401,14 +400,10 @@ class InvoiceController extends BaseController
$entityType = $invoice->getEntityType();
$message = trans("texts.created_{$entityType}");
// check if we created a new client with the invoice
// TODO: replace with HistoryListener
$input = $request->input();
$clientPublicId = isset($input['client']['public_id']) ? $input['client']['public_id'] : false;
if ($clientPublicId == '-1') {
$message = $message.' '.trans('texts.and_created_client');
$trackUrl = URL::to('clients/' . $invoice->client->public_id);
Utils::trackViewed($invoice->client->getDisplayName(), ENTITY_CLIENT, $trackUrl);
}
Session::flash('message', $message);

View File

@ -82,8 +82,6 @@ class VendorController extends BaseController
{
$vendor = $request->entity();
Utils::trackViewed($vendor->getDisplayName(), 'vendor');
$actionLinks = [
['label' => trans('texts.new_vendor'), 'url' => URL::to('/vendors/create/' . $vendor->public_id)]
];
@ -134,7 +132,7 @@ class VendorController extends BaseController
public function edit(VendorRequest $request)
{
$vendor = $request->entity();
$data = [
'vendor' => $vendor,
'method' => 'PUT',

View File

@ -481,7 +481,7 @@ if (!defined('CONTACT_EMAIL')) {
define('ACTIVITY_TYPE_UPDATE_TASK', 43);
define('DEFAULT_INVOICE_NUMBER', '0001');
define('RECENTLY_VIEWED_LIMIT', 8);
define('RECENTLY_VIEWED_LIMIT', 20);
define('LOGGED_ERROR_LIMIT', 100);
define('RANDOM_KEY_LENGTH', 32);
define('MAX_NUM_USERS', 20);

View File

@ -4,22 +4,70 @@ use Request;
use stdClass;
use Session;
use App\Models\EntityModel;
use App\Models\Activity;
class HistoryUtils
{
public static function loadHistory($users)
{
$userIds = [];
if (is_array($users)) {
foreach ($users as $user) {
$userIds[] = $user->user_id;
}
} else {
$userIds[] = $users;
}
$activityTypes = [
ACTIVITY_TYPE_CREATE_CLIENT,
ACTIVITY_TYPE_CREATE_INVOICE,
ACTIVITY_TYPE_UPDATE_INVOICE,
ACTIVITY_TYPE_EMAIL_INVOICE,
ACTIVITY_TYPE_CREATE_QUOTE,
ACTIVITY_TYPE_UPDATE_QUOTE,
ACTIVITY_TYPE_EMAIL_QUOTE,
ACTIVITY_TYPE_VIEW_INVOICE,
ACTIVITY_TYPE_VIEW_QUOTE,
];
$activities = Activity::scope()
->with('client.contacts', 'invoice')
->whereIn('user_id', $userIds)
->whereIn('activity_type_id', $activityTypes)
->orderBy('id', 'asc')
->limit(100)
->get();
foreach ($activities as $activity)
{
if ($activity->activity_type_id == ACTIVITY_TYPE_CREATE_CLIENT) {
$entity = $activity->client;
} else {
$entity = $activity->invoice;
}
static::trackViewed($entity);
}
}
public static function trackViewed(EntityModel $entity)
{
if ($entity->isEntityType(ENTITY_CREDIT) || $entity->isEntityType(ENTITY_VENDOR)) {
if ($entity->isEntityType(ENTITY_CREDIT)
|| $entity->isEntityType(ENTITY_PAYMENT)
|| $entity->isEntityType(ENTITY_VENDOR)) {
return;
}
$object = static::convertToObject($entity);
$history = Session::get(RECENTLY_VIEWED);
$history = Session::get(RECENTLY_VIEWED) ?: [];
$accountHistory = isset($history[$entity->account_id]) ? $history[$entity->account_id] : [];
$data = [];
// Add to the list and make sure to only show each item once
for ($i = 0; $i<count($history); $i++) {
$item = $history[$i];
for ($i = 0; $i<count($accountHistory); $i++) {
$item = $accountHistory[$i];
if ($object->url == $item->url) {
continue;
@ -40,8 +88,9 @@ class HistoryUtils
array_pop($data);
}
//$data = [];
Session::put(RECENTLY_VIEWED, $data);
$history[$entity->account_id] = $data;
Session::put(RECENTLY_VIEWED, $history);
}
private static function convertToObject($entity)
@ -67,12 +116,14 @@ class HistoryUtils
return $object;
}
public static function renderHtml()
public static function renderHtml($accountId)
{
$lastClientId = false;
$clientMap = [];
$str = '';
$history = Session::get(RECENTLY_VIEWED, []);
$history = isset($history[$accountId]) ? $history[$accountId] : [];
foreach ($history as $item)
{
@ -84,15 +135,14 @@ class HistoryUtils
if ($lastClientId === false || $item->client_id != $lastClientId)
{
$icon = '<i class="fa fa-users" style="width:30px"></i>';
$icon = '<i class="fa fa-users" style="width:32px"></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>
$button = '<a type="button" class="btn btn-primary btn-sm pull-right" href="' . $buttonLink . '">
<i class="fa fa-plus-circle" style="width:20px" title="' . trans('texts.create_invoice') . '"></i>
</a>';
} else {
$link = '#';
@ -108,11 +158,10 @@ class HistoryUtils
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);
$icon = '<i class="fa fa-' . EntityModel::getIcon($item->entityType . 's') . '" style="width:24px"></i>';
$str .= sprintf('<li style="text-align:right; padding-right:18px;"><a href="%s">%s %s</a></li>', $item->url, $item->name, $icon);
}
//dd($str);
return $str;
}
}

View File

@ -191,19 +191,6 @@ class Utils
return $response;
}
public static function getLastURL()
{
if (!count(Session::get(RECENTLY_VIEWED))) {
return '#';
}
$history = Session::get(RECENTLY_VIEWED);
$last = $history[0];
$penultimate = count($history) > 1 ? $history[1] : $last;
return Request::url() == $last->url ? $penultimate->url : $last->url;
}
public static function getProLabel($feature)
{
if (Auth::check()
@ -600,53 +587,6 @@ class Utils
}
}
public static function trackViewed($name, $type, $url = false)
{
/*
if (!$url) {
$url = Request::url();
}
$viewed = Session::get(RECENTLY_VIEWED);
if (!$viewed) {
$viewed = [];
}
$object = new stdClass();
$object->accountId = Auth::user()->account_id;
$object->url = $url;
$object->name = ucwords($type).': '.$name;
$data = [];
$counts = [];
for ($i = 0; $i<count($viewed); $i++) {
$item = $viewed[$i];
if ($object->url == $item->url || $object->name == $item->name) {
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[Auth::user()->account_id]) && $counts[Auth::user()->account_id] > RECENTLY_VIEWED_LIMIT) {
array_pop($data);
}
Session::put(RECENTLY_VIEWED, $data);
*/
}
public static function processVariables($str)
{
if (!$str) {

View File

@ -6,6 +6,7 @@ use Session;
use App\Events\UserLoggedIn;
use App\Events\UserSignedUp;
use App\Ninja\Repositories\AccountRepository;
use App\Libraries\HistoryUtils;
/**
* Class HandleUserLoggedIn
@ -19,7 +20,7 @@ class HandleUserLoggedIn {
/**
* Create the event handler.
*
*
* @param AccountRepository $accountRepo
*/
public function __construct(AccountRepository $accountRepo)
@ -47,10 +48,11 @@ class HandleUserLoggedIn {
$users = $this->accountRepo->loadAccounts(Auth::user()->id);
Session::put(SESSION_USER_ACCOUNTS, $users);
HistoryUtils::loadHistory($users ?: Auth::user()->id);
$account->loadLocalizationSettings();
// if they're using Stripe make sure they're using Stripe.js
// if they're using Stripe make sure they're using Stripe.js
$accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE);
if ($accountGateway && ! $accountGateway->getPublishableStripeKey()) {
Session::flash('warning', trans('texts.missing_publishable_key'));

View File

@ -286,7 +286,6 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
public function clearSession()
{
$keys = [
RECENTLY_VIEWED,
SESSION_USER_ACCOUNTS,
SESSION_TIMEZONE,
SESSION_DATE_FORMAT,

View File

@ -53,6 +53,7 @@ elixir(function(mix) {
'bootstrap-combobox.css',
'typeahead.js-bootstrap.css',
'style.css',
'sidebar.css',
'fonts.css'
], 'public/css/built.css');

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

213
resources/assets/css/sidebar.css vendored Normal file
View File

@ -0,0 +1,213 @@
/*!
* Start Bootstrap - Simple Sidebar (http://startbootstrap.com/)
* Copyright 2013-2016 Start Bootstrap
* Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
*/
@media(min-width:768px) {
body {
overflow-x: hidden;
}
/* Toggle Styles */
#wrapper {
padding-left: 0;
padding-right: 0;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
#wrapper.toggled-left {
padding-left: 250px;
}
#wrapper.toggled-right {
padding-right: 250px;
}
#left-sidebar-wrapper {
z-index: 1000;
position: fixed;
left: 250px;
width: 0;
height: 100%;
margin-left: -250px;
overflow-y: auto;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
#right-sidebar-wrapper {
z-index: 1000;
position: fixed;
right: 250px;
width: 0px;
height: 100%;
margin-right: -250px;
overflow-y: auto;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
#wrapper.toggled-left #left-sidebar-wrapper {
width: 250px;
}
#wrapper.toggled-right #right-sidebar-wrapper {
width: 250px;
}
#page-content-wrapper {
width: 100%;
position: absolute;
padding: 15px;
}
#wrapper.toggled-left #page-content-wrapper {
position: absolute;
margin-right: -250px;
}
#wrapper.toggled-right #page-content-wrapper {
position: absolute;
padding-right: -250px;
}
/* Sidebar Styles */
.sidebar-nav {
padding-top: 16px;
position: absolute;
top: 0;
width: 250px;
margin: 0;
list-style: none;
height: 100%;
}
#left-sidebar-wrapper .sidebar-nav li {
text-indent: 20px;
line-height: 40px;
}
#right-sidebar-wrapper .sidebar-nav li {
text-indent: 8px;
font-size: 16px;
line-height: 44px;
}
#right-sidebar-wrapper .sidebar-nav li a.btn {
margin-top:5px;
margin-right:10px;
text-indent:0px
}
.sidebar-nav li > a {
display: block;
text-decoration: none;
cursor: pointer;
}
.sidebar-nav li:hover > a,
.sidebar-nav li > a.active {
text-decoration: none;
}
.sidebar-nav li > a:hover {
text-decoration: none;
}
.sidebar-nav li > a.btn {
display: none;
}
.sidebar-nav li:hover > a {
display: block;
}
.sidebar-nav > .sidebar-brand {
height: 65px;
font-size: 18px;
line-height: 60px;
}
.sidebar-nav > .sidebar-brand a {
color: #999999;
}
.sidebar-nav > .sidebar-brand a:hover {
color: #fff;
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;
}
#wrapper {
padding-left: 250px;
padding-right: 250px;
}
#wrapper.toggled-left {
padding-left: 0;
}
#wrapper.toggled-right {
padding-right: 0;
}
#left-sidebar-wrapper {
width: 250px;
}
#right-sidebar-wrapper {
width: 250px;
}
#wrapper.toggled-left #left-sidebar-wrapper {
width: 0;
}
#wrapper.toggled-right #right-sidebar-wrapper {
width: 0;
}
#page-content-wrapper {
padding: 20px;
position: relative;
}
#wrapper.toggled-left #page-content-wrapper {
position: relative;
margin-right: 0;
}
#wrapper.toggled-right #page-content-wrapper {
position: relative;
margin-right: 0;
}
.menu-toggle {
text-decoration: none;
}
.menu-toggle:hover {
text-decoration: none;
}
}

View File

@ -1,4 +1,5 @@
body { background: #f8f8f8 !important;
body {
padding-top: 56px;
font-family: 'Roboto', sans-serif;
font-size: 15px;
}
@ -71,10 +72,7 @@ table.data-table td {
table.dataTable { border-radius: 3px; border-collapse: collapse;
/*border-spacing: 0;*/}
table.dataTable thead > tr > th, table.invoice-table thead > tr > th {
background-color: #e37329 !important;
color:#fff;
}
/*
table.dataTable tr:hover {
background-color: #F2F5FE !important;
@ -89,7 +87,6 @@ th:last-child {
}
tr {border: none;}
thead th {border-left: 1px solid #d26b26;}
tbody td {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;

View File

@ -7,236 +7,117 @@
<style type="text/css">
.menu-toggle {
color: #999 !important;
text-decoration: none;
body {
background: #f8f8f8;
}
table.dataTable thead > tr > th,
table.invoice-table thead > tr > th {
background-color: #e37329 !important;
color:#fff;
}
thead th {
border-left: 1px solid #d26b26;
}
.sidebar-nav {
background-color: #222;
}
.sidebar-nav li {
border-bottom:solid 1px;
}
.sidebar-nav i.fa {
color: white;
}
.menu-toggle i,
.sidebar-nav li > a {
color: #999999;
}
.menu-toggle:hover i,
.sidebar-nav li:hover > a,
.sidebar-nav li > a.active {
color: #fff;
}
.sidebar-nav li:hover,
.sidebar-nav li.active {
background: rgba(255,255,255,0.2);
}
.menu-toggle {
color: #999 !important;
}
.menu-toggle:hover {
color: #fff !important;
}
.menu-toggle {
text-decoration: none;
}
.menu-toggle:hover {
text-decoration: none;
}
/*
body {
background: white;
}
.menu-toggle:hover {
color: #fff !important;
text-decoration: none;
div.panel-body {
background-color: #f2f5fe;
}
/*!
* Start Bootstrap - Simple Sidebar (http://startbootstrap.com/)
* Copyright 2013-2016 Start Bootstrap
* Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
*/
body {
overflow-x: hidden;
}
/* Toggle Styles */
#wrapper {
padding-left: 0;
padding-right: 0;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
table.dataTable thead > tr > th,
table.invoice-table thead > tr > th {
background-color: #0b4d78 !important;
color:#fff;
}
#wrapper.toggled-left {
padding-left: 250px;
thead th {
border-left: 1px solid #7a8799;
}
#wrapper.toggled-right {
padding-right: 250px;
}
#left-sidebar-wrapper {
z-index: 1000;
position: fixed;
left: 250px;
width: 0;
height: 100%;
margin-left: -250px;
overflow-y: auto;
background: #222;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
#right-sidebar-wrapper {
z-index: 1000;
position: fixed;
right: 250px;
width: 0px;
height: 100%;
margin-right: -250px;
overflow-y: auto;
background: #222;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
#wrapper.toggled-left #left-sidebar-wrapper {
width: 250px;
}
#wrapper.toggled-right #right-sidebar-wrapper {
width: 250px;
}
#page-content-wrapper {
width: 100%;
position: absolute;
padding: 15px;
}
#wrapper.toggled-left #page-content-wrapper {
position: absolute;
margin-right: -250px;
}
#wrapper.toggled-right #page-content-wrapper {
position: absolute;
padding-right: -250px;
}
/* Sidebar Styles */
.sidebar-nav {
padding-top: 16px;
position: absolute;
top: 0;
width: 250px;
margin: 0;
list-style: none;
height: 100%;
background-color: #f2f5fe;
}
.sidebar-nav i.fa {
color: white;
color: #7a8799;
}
.sidebar-nav li {
border-bottom:solid 1px;
}
#left-sidebar-wrapper .sidebar-nav li {
text-indent: 20px;
line-height: 40px;
}
#right-sidebar-wrapper .sidebar-nav li {
text-indent: 10px;
font-size: 16px;
line-height: 44px;
border-bottom:solid 1px #7a8799;
}
.sidebar-nav li > a {
display: block;
text-decoration: none;
color: #999999;
cursor: pointer;
color: #7a8799;
}
.sidebar-nav li:hover > a,
.sidebar-nav li > a.active {
text-decoration: none;
color: #fff;
color: #2b435d;
}
.sidebar-nav li:hover,
.sidebar-nav li.active {
background: rgba(255,255,255,0.2);
background: rgba(255,255,255,1);
}
.sidebar-nav li > a:hover {
text-decoration: none;
.menu-toggle {
color: #999 !important;
}
.sidebar-nav li > a.btn {
display: none;
.menu-toggle:hover {
color: #fff !important;
}
.sidebar-nav li:hover > a {
display: block;
}
.sidebar-nav > .sidebar-brand {
height: 65px;
font-size: 18px;
line-height: 60px;
}
.sidebar-nav > .sidebar-brand a {
color: #999999;
}
.sidebar-nav > .sidebar-brand a:hover {
color: #fff;
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) {
#wrapper {
padding-left: 250px;
padding-right: 250px;
}
#wrapper.toggled-left {
padding-left: 0;
}
#wrapper.toggled-right {
padding-right: 0;
}
#left-sidebar-wrapper {
width: 250px;
}
#right-sidebar-wrapper {
width: 250px;
}
#wrapper.toggled-left #left-sidebar-wrapper {
width: 0;
}
#wrapper.toggled-right #right-sidebar-wrapper {
width: 0;
}
#page-content-wrapper {
padding: 20px;
position: relative;
}
#wrapper.toggled-left #page-content-wrapper {
position: relative;
margin-right: 0;
}
#wrapper.toggled-right #page-content-wrapper {
position: relative;
margin-right: 0;
}
}
body {
background-color: #EEEEEE;
padding-top: 56px;
}
*/
@if (Auth::check() && Auth::user()->dark_mode)
body {
@ -594,19 +475,21 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<div class="navbar-brand">
<a href="#" id="left-menu-toggle" class="menu-toggle hide-phone" title="{{ trans('texts.toggle_navigation') }}">
<i class="fa fa-bars" style="width:30px;padding-right:10px"></i>
</a>
<a href="{{ URL::to(NINJA_WEB_URL) }}" target="_blank">
{{-- Per our license, please do not remove or modify this link. --}}
<img src="{{ asset('images/invoiceninja-logo.png') }}" width="193" height="25"/>
</a>
</div>
<a href="#" id="left-menu-toggle" class="menu-toggle" title="{{ trans('texts.toggle_navigation') }}">
<div class="navbar-brand">
<i class="fa fa-bars hide-phone" style="width:30px;padding-top:2px;float:left"></i>
{{-- Per our license, please do not remove or modify this link. --}}
<img src="{{ asset('images/invoiceninja-logo.png') }}" width="193" height="25" style="float:left"/>
</div>
</a>
</div>
<a id="right-menu-toggle" class="menu-toggle hide-phone pull-right" title="{{ trans('texts.toggle_history') }}" style="cursor:pointer">
<div class="fa fa-bars" style="width:30px;margin-right:18px;margin-left:24px;margin-top:20px;margin-bottom:25px;text-align:center"></div>
</a>
<div class="collapse navbar-collapse" id="navbar-collapse-1">
<div class="navbar-form navbar-right" style="padding-right:30px">
<div class="navbar-form navbar-right">
@if (Auth::check())
@if (!Auth::user()->registered)
@ -673,10 +556,6 @@
</ul>
</div>
<a href="#" id="right-menu-toggle" class="menu-toggle hide-phone" title="{{ trans('texts.toggle_history') }}">
<i class="fa fa-bars" style="width:30px;padding-left:14px"></i>
</a>
</div>
<form id="search-form" class="navbar-form navbar-right" role="search">
@ -723,7 +602,7 @@
<div id="wrapper" class='{!! session(SESSION_LEFT_SIDEBAR) ? 'toggled-left' : '' !!} {!! session(SESSION_RIGHT_SIDEBAR, true) ? 'toggled-right' : '' !!}'>
<!-- Sidebar -->
<div id="left-sidebar-wrapper">
<div id="left-sidebar-wrapper" class="hide-phone">
<ul class="sidebar-nav">
@foreach([
'dashboard',
@ -759,9 +638,9 @@
</div>
<!-- /#left-sidebar-wrapper -->
<div id="right-sidebar-wrapper">
<div id="right-sidebar-wrapper" class="hide-phone">
<ul class="sidebar-nav">
{!! \App\Libraries\HistoryUtils::renderHtml() !!}
{!! \App\Libraries\HistoryUtils::renderHtml(Auth::user()->account_id) !!}
</ul>
</div>
@ -795,7 +674,7 @@
@endif
@yield('content')
<br/>
<div class="row">
<div class="col-md-12">

View File

@ -88,7 +88,7 @@
@endif
{!! Former::close() !!}
<script type="text/javascript">
function submitForm(action) {