Made big headway in preference management, accounts, importing stuff, etc. etc.

This commit is contained in:
James Cole 2014-07-06 15:18:11 +02:00
parent 188105492c
commit 4192f2bc8f
46 changed files with 672 additions and 187 deletions

View File

@ -36,6 +36,7 @@ return [
'Illuminate\Validation\ValidationServiceProvider',
'Illuminate\View\ViewServiceProvider',
'Illuminate\Workbench\WorkbenchServiceProvider',
'Grumpydictator\Gchart\GchartServiceProvider',
'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
'Barryvdh\Debugbar\ServiceProvider',
'Firefly\Storage\StorageServiceProvider',

View File

@ -1,23 +1,50 @@
<?php
//use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
class AccountController extends \BaseController
{
// public function __construct(ARI $accounts) {
// $this->accounts = $accounts;
// }
//
// /**
// * Display a listing of the resource.
// *
// * @return Response
// */
// public function index()
// {
//
// }
public function __construct(ARI $accounts) {
$this->accounts = $accounts;
View::share('menu', 'accounts');
}
/**
* Display a listing of the resource.
*
* @return Response
*/
public function index()
{
$all = $this->accounts->get();
$list = [
'personal' => [],
'beneficiaries' => [],
'initial' => [],
'cash' => []
];
foreach($all as $account) {
switch($account->accounttype->description) {
case 'Default account':
$list['personal'][] = $account;
break;
case 'Cash account':
$list['cash'][] = $account;
break;
case 'Initial balance account':
$list['initial'][] = $account;
break;
case 'Beneficiary account':
$list['beneficiaries'][] = $account;
break;
}
}
return View::make('accounts.index')->with('accounts',$list);
}
//
//
/**
@ -46,16 +73,16 @@ class AccountController extends \BaseController
// }
//
//
// /**
// * Display the specified resource.
// *
// * @param int $id
// * @return Response
// */
// public function show($id)
// {
// //
// }
/**
* Display the specified resource.
*
* @param Account $account
* @return Response
*/
public function show(Account $account)
{
}
//
//
// /**

View File

@ -0,0 +1,61 @@
<?php
use Carbon\Carbon as Carbon;
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
class ChartController extends BaseController
{
public function __construct(ARI $accounts)
{
$this->accounts = $accounts;
}
/**
* Show home charts.
*/
public function home(Account $account = null)
{
// chart
$chart = App::make('gchart');
$chart->addColumn('Day of the month', 'date');
// date
$today = new Carbon;
$past = clone $today;
$past->subMonth();
$current = clone $past;
if (is_null($account)) {
// get accounts:
$accounts = $this->accounts->getActiveDefault();
foreach ($accounts as $account) {
$chart->addColumn($account->name, 'number');
}
while ($current <= $today) {
$row = [clone $current];
// loop accounts:
foreach ($accounts as $account) {
$row[] = $account->balance(clone $current);
}
$current->addDay();
$chart->addRowArray($row);
}
} else {
$chart->addColumn($account->name, 'number');
while ($current <= $today) {
$row = [clone $current,$account->balance(clone $current)];
$current->addDay();
$chart->addRowArray($row);
}
}
$chart->generate();
return $chart->getData();
}
}

View File

@ -1,19 +1,35 @@
<?php
use Carbon\Carbon as Carbon;
use Firefly\Helper\Preferences\PreferencesHelperInterface as PHI;
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
class HomeController extends BaseController {
public function __construct(ARI $accounts) {
class HomeController extends BaseController
{
protected $accounts;
protected $preferences;
public function __construct(ARI $accounts, PHI $preferences)
{
$this->accounts = $accounts;
$this->preferences = $preferences;
View::share('menu', 'home');
}
public function index()
{
public function index()
{
// get list setting:
$pref = $this->preferences->get('frontpageAccounts', []);
// get the accounts to display on the home screen:
$count = $this->accounts->count();
if ($pref->data == []) {
$list = $this->accounts->getActiveDefault();
} else {
$list = $this->accounts->getByIds($pref->data);
}
// build the home screen:
return View::make('index')->with('count',$count);
}
return View::make('index')->with('count', $count)->with('accounts', $list);
}
}

View File

@ -9,6 +9,7 @@ class MigrationController extends BaseController
public function __construct(MHI $migration)
{
$this->migration = $migration;
View::share('menu', 'home');
}

View File

@ -0,0 +1,39 @@
<?php
use Firefly\Helper\Preferences\PreferencesHelperInterface as PHI;
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
class PreferencesController extends BaseController
{
protected $accounts;
protected $preferences;
public function __construct(ARI $accounts, PHI $preferences)
{
$this->accounts = $accounts;
$this->preferences = $preferences;
View::share('menu', 'home');
}
public function index()
{
$accounts = $this->accounts->getDefault();
// pref:
$frontpage = $this->preferences->get('frontpageAccounts', []);
return View::make('preferences.index')->with('accounts', $accounts)->with('frontpageAccounts', $frontpage);
}
public function postIndex()
{
$frontpageAccounts = [];
foreach(Input::get('frontpageAccounts') as $id) {
$frontpageAccounts[] = intval($id);
}
$this->preferences->set('frontpageAccounts',$frontpageAccounts);
Session::flash('success', 'Preferences saved!');
return Redirect::route('preferences');
}
}

View File

@ -7,6 +7,7 @@ class ProfileController extends BaseController
public function __construct(URI $user) {
$this->user = $user;
View::share('menu', 'home');
}
public function index()

View File

@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreatePreferencesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'preferences', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('user_id')->unsigned();
$table->string('name');
$table->text('data');
// connect preferences to users
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('preferences');
}
}

View File

@ -1,11 +1,5 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 03/07/14
* Time: 21:06
*/
class DefaultUserSeeder extends Seeder
{
public function run()

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 04/07/14
* Time: 13:58
*/
namespace Firefly\Exception;

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 04/07/14
* Time: 13:55
*/
namespace Firefly\Helper;

View File

@ -21,6 +21,12 @@ class HelperServiceProvider extends ServiceProvider
'Firefly\Helper\Migration\MigrationHelperInterface',
'Firefly\Helper\Migration\MigrationHelper'
);
// settings:
$this->app->bind(
'Firefly\Helper\Preferences\PreferencesHelperInterface',
'Firefly\Helper\Preferences\PreferencesHelper'
);
}
}

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 03/07/14
* Time: 21:34
*/
namespace Firefly\Helper\Migration;

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 03/07/14
* Time: 21:33
*/
namespace Firefly\Helper\Migration;

View File

@ -0,0 +1,39 @@
<?php
namespace Firefly\Helper\Preferences;
class PreferencesHelper implements PreferencesHelperInterface
{
public function get($name, $default = null)
{
$pref = \Preference::where('user_id', \Auth::user()->id)->where('name', $name)->first();
if (is_null($default) && is_null($pref)) {
// return NULL
return null;
}
if (!is_null($pref)) {
return $pref;
}
if (!is_null($default) && is_null($pref)) {
// create preference, return that:
return $this->set($name, $default);
}
}
public function set($name, $value)
{
$pref = \Preference::where('user_id', \Auth::user()->id)->where('name', $name)->first();
if (is_null($pref)) {
$pref = new \Preference;
$pref->name = $name;
$pref->user()->associate(\Auth::user());
}
$pref->data = $value;
$pref->save();
return $pref;
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Firefly\Helper\Preferences;
interface PreferencesHelperInterface
{
public function set($name,$value);
public function get($name,$default = null);
}

View File

@ -10,6 +10,9 @@ interface AccountRepositoryInterface
public function count();
public function get();
public function getByIds($ids);
public function getDefault();
public function getActiveDefault();
public function store($data);
public function storeWithInitialBalance($data,\Carbon\Carbon $date, $amount = 0);

View File

@ -3,8 +3,6 @@
namespace Firefly\Storage\Account;
use Firefly\Helper\MigrationException;
class EloquentAccountRepository implements AccountRepositoryInterface
{
public $validator;
@ -13,8 +11,30 @@ class EloquentAccountRepository implements AccountRepositoryInterface
{
}
public function get() {
return \Auth::user()->accounts()->get();
public function get()
{
return \Auth::user()->accounts()->with('accounttype')->get();
}
public function getByIds($ids)
{
return \Auth::user()->accounts()->with('accounttype')->whereIn('id', $ids)->get();
}
public function getDefault()
{
return \Auth::user()->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where('account_types.description', 'Default account')
->get(['accounts.*']);
}
public function getActiveDefault()
{
return \Auth::user()->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where('account_types.description', 'Default account')->where('accounts.active', 1)
->get(['accounts.*']);
}
public function count()

View File

@ -1,10 +1,5 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 03/07/14
* Time: 15:24
*/
namespace Firefly\Storage\TransactionJournal;
@ -15,7 +10,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
public function createSimpleJournal(\Account $from, \Account $to, $description, $amount, \Carbon\Carbon $date)
{
\Log::debug('Creating tranaction "'.$description.'".');
\Log::debug('Creating tranaction "' . $description . '".');
/*
* We're building this thinking the money goes from A to B.
* If the amount is negative however, the money still goes
@ -69,7 +64,10 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
}
// some debug information:
\Log::debug($journalType->type.': AccountFrom "'.$from->name.'" will gain/lose '.$amountFrom.' and AccountTo "'.$to->name.'" will gain/lose '.$amountTo);
\Log::debug(
$journalType->type . ': AccountFrom "' . $from->name . '" will gain/lose ' . $amountFrom
. ' and AccountTo "' . $to->name . '" will gain/lose ' . $amountTo
);
if (is_null($journalType)) {
\Log::error('Could not figure out transacion type!');

View File

@ -1,15 +1,10 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 03/07/14
* Time: 15:22
*/
namespace Firefly\Storage\TransactionJournal;
interface TransactionJournalRepositoryInterface {
interface TransactionJournalRepositoryInterface
{
public function createSimpleJournal(\Account $from, \Account $to, $description, $amount, \Carbon\Carbon $date);

View File

@ -6,7 +6,7 @@ class Account extends Elegant
public static $rules
= [
'name' => 'required|between:1,100',
'name' => 'required|between:1,100',
'user_id' => 'required|exists:users,id'
];
@ -15,17 +15,11 @@ class Account extends Elegant
return $this->belongsTo('AccountType');
}
public function transactions()
{
return $this->hasMany('Transaction');
}
public function user()
{
return $this->belongsTo('User');
}
/**
* Get an accounts current balance.
*
@ -36,7 +30,15 @@ class Account extends Elegant
public function balance(\Carbon\Carbon $date = null)
{
$date = is_null($date) ? new \Carbon\Carbon : $date;
return floatval($this->transactions()->sum('amount'));
return $this->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d'))->sum('transactions.amount');
}
public function transactions()
{
return $this->hasMany('Transaction');
}
}

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 05/07/14
* Time: 18:24
*/
class Budget extends Component {
protected $isSubclass = true;

View File

@ -4,21 +4,21 @@
class Component extends Firefly\Database\SingleTableInheritanceEntity
{
protected $table = 'components';
protected $subclassField = 'class';
public static $rules
= [
'user_id' => 'exists:users,id|required',
'name' => 'required|between:1,255',
'class' => 'required',
'component_type_id' => 'required|exists:component_types,id'
];
protected $table = 'components';
protected $subclassField = 'class';
public function transactions()
{
return $this->belongsToMany('Transaction');
}
public function transactionjournals()
{
return $this->belongsToMany('TransactionJournal');

27
app/models/Preference.php Normal file
View File

@ -0,0 +1,27 @@
<?php
class Preference extends Elegant
{
public static $rules
= [
'user_id' => 'required|exists:user,id',
'name' => 'required|between:1,255',
'data' => 'required'
];
public function user()
{
return $this->belongsTo('User');
}
public function setDataAttribute($value)
{
$this->attributes['data'] = json_encode($value);
}
public function getDataAttribute($value)
{
return json_decode($value);
}
}

View File

@ -36,4 +36,9 @@ class User extends Elegant implements UserInterface, RemindableInterface
return $this->hasMany('Account');
}
public function preferences()
{
return $this->hasMany('Preference');
}
}

View File

@ -1,4 +1,13 @@
<?php
Route::bind('account', function ($value, $route) {
if(Auth::user()) {
return Auth::user()->accounts()->find($value);
} else {
return null;
}
});
// protected routes:
Route::group(['before' => 'auth'], function () {
@ -6,6 +15,12 @@ Route::group(['before' => 'auth'], function () {
// home controller
Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index']);
// chart controller
Route::get('/chart/home/{account?}', ['uses' => 'ChartController@home', 'as' => 'chart.home']);
// preferences controller
Route::get('/preferences', ['uses' => 'PreferencesController@index', 'as' => 'preferences']);
// user controller
Route::get('/logout', ['uses' => 'UserController@logout', 'as' => 'logout']);
@ -13,11 +28,14 @@ Route::group(['before' => 'auth'], function () {
Route::get('/profile', ['uses' => 'ProfileController@index', 'as' => 'profile']);
Route::get('/profile/change-password',['uses' => 'ProfileController@changePassword', 'as' => 'change-password']);
// account controller:
Route::get('/accounts', ['uses' => 'AccountController@index', 'as' => 'accounts.index']);
Route::get('/accounts/create', ['uses' => 'AccountController@create', 'as' => 'accounts.create']);
Route::get('/accounts/{account}', ['uses' => 'AccountController@show', 'as' => 'accounts.show']);
// migration controller
Route::get('/migrate', ['uses' => 'MigrationController@index', 'as' => 'migrate']);
// account controller:
Route::get('/accounts/create', ['uses' => 'AccountController@create', 'as' => 'accounts.create']);
}
);
@ -29,6 +47,9 @@ Route::group(['before' => 'csrf|auth'], function () {
// migration controller
Route::post('/migrate', ['uses' => 'MigrationController@postIndex']);
// preferences controller
Route::post('/preferences', ['uses' => 'PreferencesController@postIndex']);
// account controller:
Route::get('/accounts/store', ['uses' => 'AccountController@store', 'as' => 'accounts.store']);

File diff suppressed because one or more lines are too long

View File

@ -1,17 +0,0 @@
<?php
class ExampleTest extends TestCase {
/**
* A basic functional test example.
*
* @return void
*/
public function testBasicExample()
{
$crawler = $this->client->request('GET', '/login');
$this->assertTrue($this->client->getResponse()->isOk());
}
}

View File

@ -1,5 +1,7 @@
<?php
class AccountControllerTest extends TestCase {
class AccountControllerTest extends TestCase
{
public function setUp()
{
parent::setUp();
@ -8,6 +10,7 @@ class AccountControllerTest extends TestCase {
public function testCreate()
{
// mock:
View::shouldReceive('share');
View::shouldReceive('make')->with('accounts.create');
// call
@ -16,4 +19,11 @@ class AccountControllerTest extends TestCase {
// test
$this->assertResponseOk();
}
public function testShow()
{
// the route filters on accounts using Eloquent, maybe fix that instead?
$this->assertTrue(true);
}
}

View File

@ -10,13 +10,25 @@ class HomeControllerTest extends TestCase
public function testIndex()
{
// mock:
View::shouldReceive('share');
View::shouldReceive('make')->with('index')->once()->andReturn(\Mockery::self())
->shouldReceive('with')->once() // Pass a 'with' parameter
->with('count', 0)
;
->andReturn(Mockery::self())
->shouldReceive('with')->once() // another 'with' parameter.
->with('accounts',[])
->andReturn(Mockery::self())
;
Auth::shouldReceive('check')->andReturn(true);
// mock account repository
$accounts = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface');
$accounts->shouldReceive('count')->andReturn(0);
$accounts->shouldReceive('getActiveDefault')->andReturn([]);
// mock preferences helper:
$preferences = $this->mock('Firefly\Helper\Preferences\PreferencesHelperInterface');
$preferences->shouldReceive('get')->with('frontpageAccounts',[])->andReturn(new \Preference)->once();
// call
$this->call('GET', '/');

View File

@ -10,6 +10,7 @@ class MigrationControllerTest extends TestCase
public function testIndex()
{
// mock:
View::shouldReceive('share');
View::shouldReceive('make')->with('migrate.index');
// call

View File

@ -6,6 +6,7 @@ class ProfileControllerTest extends TestCase
public function testIndex()
{
// mock:
View::shouldReceive('share');
View::shouldReceive('make')->with('profile.index');
// call
@ -18,6 +19,7 @@ class ProfileControllerTest extends TestCase
public function testChangePassword()
{
// mock:
View::shouldReceive('share');
View::shouldReceive('make')->with('profile.change-password');
// call

View File

@ -0,0 +1,30 @@
<?php
class TransactionJournalTest extends TestCase
{
/**
* Default preparation for each test
*/
public function setUp()
{
parent::setUp();
$this->prepareForTests();
}
/**
* Migrate the database
*/
private function prepareForTests()
{
Artisan::call('migrate');
}
/**
* Test accounts
*/
public function testJournal()
{
$this->assertTrue(true);
}
}

View File

@ -68,11 +68,8 @@ class UserTest extends TestCase
$account->save();
$this->assertCount(1,$user->accounts()->get());
}
}

View File

@ -0,0 +1,53 @@
@extends('layouts.default')
@section('content')
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h1>Firefly
<small>Accounts</small>
</h1>
<h2>Index</h2>
<p style="width:50%;" class="text-info">
In a double-entry bookkeeping system almost <em>everything</em> is an account. Your own personal
bank accounts are representated as accounts (naturally), but the stores you buy stuff at are also
represented as accounts. Likewise, if you have a job, your salary is drawn from their account.
</p>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h3>Your accounts</h3>
<p style="width:50%;" class="text-info">
These are your personal accounts.
</p>
@include('accounts.list',['accounts' => $accounts['personal']])
<h3>Beneficiaries</h3>
<p style="width:50%;" class="text-info">
These are beneficiaries; places where you spend money or people who pay you.
</p>
@include('accounts.list',['accounts' => $accounts['beneficiaries']])
<h3>Initial balances</h3>
<p style="width:50%;" class="text-info">
These are system accounts; created to add balance to the books when you add a personal account
which already has money in it. That money has to come from somewhere.
</p>
@include('accounts.list',['accounts' => $accounts['initial']])
<h3>Cash</h3>
<p style="width:50%;" class="text-info">
This is a system account. When you don't specify a beneficiary or draw many from an ATM (or put cash in your
personal accounts) it gets added or drawn from this account.
</p>
@include('accounts.list',['accounts' => $accounts['cash']])
</div>
</div>
@stop
@section('scripts')
<script src="https://www.google.com/jsapi"></script>
<!-- <script src="assets/javascript/charts.js"></script>-->
<!-- <script src="assets/javascript/index.js"></script>-->
@stop

View File

@ -0,0 +1,19 @@
<table class="table table-bordered table-striped">
<tr>
<th style="width:25px;">&nbsp;</th>
<th style="width:30%;">Name</th>
<th>Current balance</th>
</tr>
@foreach($accounts as $account)
<tr>
<td>
@if($account->active == 0)
<span title="This account is inactive." class="glyphicon glyphicon-ban-circle"></span>
@endif
</td>
<td>
<a href="{{route('accounts.show',$account->id)}}" title="Overview for account {{{$account->name}}}">{{{$account->name}}}</a></td>
<td>{{mf($account->balance())}}</td>
</tr>
@endforeach
</table>

View File

@ -4,7 +4,6 @@
<div class="col-lg-12 col-md-12 col-sm-12">
<h1>Firefly
@if($count > 0)
<br/>
<small>What's playing?</small>
@endif
</h1>
@ -33,10 +32,27 @@
</p>
</div>
@else
<div class="row" style="border-top:1px #eee solid;">
@foreach($accounts as $index => $account)
<div class="col-lg-6">
<div id="chart_{{{$account->id}}}" data-id="{{{$account->id}}}" class="homeChart" data-title="{{{$account->name}}}"></div>
<p>
Go to <a href="#" title="Overview for {{{$account->name}}}">{{{$account->name}}}</a>
</p>
</div>
@if($index % 2 == 1)
</div><div class="row" style="border-top:1px #eee solid;">
@endif
@endforeach
</div>
@endif
@stop
@section('scripts')
<script src="https://www.google.com/jsapi"></script>
<script src="assets/javascript/charts.js"></script>
<script src="assets/javascript/index.js"></script>
@stop

View File

@ -19,7 +19,7 @@
</head>
<body>
<div class="container">
@include('partials.menu')
@include('partials.menu.'.$menu)
@include('partials.flashes')
@yield('content')
</div>

View File

@ -0,0 +1,27 @@
<?php
$r = Route::current()->getName();
?>
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{route('index')}}">Firefly III</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li @if($r=='index')class="active"@endif><a href="{{route('index')}}">Home</a></li>
<li @if($r=='accounts.index')class="active"@endif><a href="{{route('accounts.index')}}">Accounts</a></li>
<li @if($r=='accounts.create')class="active"@endif><a href="{{route('accounts.create')}}"><span class="glyphicon glyphicon-plus"></span> Create</a></li>
</ul>
@include('partials.menu.shared')
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>

View File

@ -1,3 +1,6 @@
<?php
$r = Route::current()->getName();
?>
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
@ -14,12 +17,11 @@
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li @if($r=='index')class="active"@endif><a href="{{route('index')}}">Home</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Go to...<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#">Action</a></li>
<li><a href="{{route('accounts.index')}}">Accounts</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li class="divider"></li>
@ -29,23 +31,7 @@
</ul>
</li>
</ul>
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">{{{Auth::user()->email}}} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="{{route('profile')}}"><span class="glyphicon glyphicon-user"></span> Profile</a></li>
<li class="divider"></li>
<li><a href="{{route('logout')}}"><span class="glyphicon glyphicon-arrow-right"></span> Logout</a></li>
</ul>
</li>
</ul>
@include('partials.menu.shared')
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>

View File

@ -0,0 +1,11 @@
<ul class="nav navbar-nav navbar-right">
<li @if($r=='settings')class="active"@endif><a href="{{route('preferences')}}"><span class="glyphicon glyphicon-cog"></span> Preferences</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">{{{Auth::user()->email}}} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="{{route('profile')}}"><span class="glyphicon glyphicon-user"></span> Profile</a></li>
<li class="divider"></li>
<li><a href="{{route('logout')}}"><span class="glyphicon glyphicon-arrow-right"></span> Logout</a></li>
</ul>
</li>
</ul>

View File

@ -0,0 +1,45 @@
@extends('layouts.default')
@section('content')
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h1>Firefly
<small>Preferences</small>
</h1>
</div>
</div>
<!-- home screen accounts -->
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h3>Home screen accounts</h3>
<p class="text-info">Which accounts should be displayed on the home page?</p>
<!-- form -->
{{Form::open(['class' => 'form-horizontal'])}}
@foreach($accounts as $account)
<div class="form-group">
<div class="col-sm-10">
<div class="checkbox">
<label>
@if(in_array($account->id,$frontpageAccounts->data) || count($frontpageAccounts->data) == 0)
<input type="checkbox" name="frontpageAccounts[]" value="{{$account->id}}" checked> {{{$account->name}}}
@else
<input type="checkbox" name="frontpageAccounts[]" value="{{$account->id}}"> {{{$account->name}}}
@endif
</label>
</div>
</div>
</div>
@endforeach
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-default">Save accounts</button>
</div>
</div>
</form>
</div>
</div>
@stop
@section('scripts')
@stop

View File

@ -13,7 +13,7 @@
if (!function_exists('mf')) {
function mf($n, $coloured = false)
function mf($n, $coloured = true)
{
$n = floatval($n);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,21 @@
function drawChart(id,URL,opt) {
$.getJSON(URL).success(function (data) {
$(id).removeClass('loading');
// actually draw chart.
var gdata = new google.visualization.DataTable(data);
var money = new google.visualization.NumberFormat({decimalSymbol: ',', groupingSymbol: '.', prefix: '€ '});
money.format(gdata, 1);
var gID = id.substring(1);
var chart = new google.visualization.LineChart(document.getElementById(gID));
chart.draw(gdata, opt);
}).fail(function() {
console.log('Could not load chart for URL ' + URL);
$(id).addClass('load-error');
});
}

View File

@ -1,34 +1,38 @@
// Get context with jQuery - using jQuery's .get() method.
var ctx = $("#myChart").get(0).getContext("2d");
// This will get the first returned node in the jQuery collection.
google.load('visualization', '1.0', {'packages': ['corechart']});
google.setOnLoadCallback(chartCallback);
// grab data from JSON point somewhere?
function chartCallback() {
drawAccountChart();
}
function drawAccountChart() {
var data = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
label: "My First dataset",
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: [65, 59, 80, 81, 56, 55, 40]
var opt = {
curveType: 'function',
legend: {
position: 'none'
},
{
label: "My Second dataset",
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
data: [28, 48, 40, 19, 86, 27, 90]
}
]
};
options = [];
var myLineChart = new Chart(ctx).Line(data, options);
chartArea: {
left: 50,
top: 10,
width: '90%',
height: 180
},
height: 230
};
$.each($('.homeChart'), function (i, v) {
var obj = $(v);
var accountID = obj.data('id').toString();
var holderID = $(v).attr('id').toString();
console.log('AccountID: ' + accountID + ', ' + 'holderID ' + holderID);
var URL = 'chart/home/' + accountID;
console.log('URL: ' + URL);
// draw it!
drawChart('#' + holderID,URL, opt);
});
//var URL = 'chart/home';
//drawChart('#chart',URL,opt);
}