test dashboard data
This commit is contained in:
hackerESQ
2024-08-06 22:59:17 -05:00
parent 38e07cadd7
commit eb260b2990
10 changed files with 205 additions and 227 deletions
@@ -0,0 +1,26 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use stdClass;
class DashboardController extends Controller
{
/**
* Display the specified resource.
*/
public function show(Request $request)
{
$user = $request->user()->load('portfolios');
$dashboard = new stdClass;
$dashboard->marketGainLoss = rand(-200, 3999);
$dashboard->totalCostBasis = rand(-200, 3999);
$dashboard->totalMarketValue = rand(-200, 3999);
$dashboard->realizedGainLoss = rand(-200, 3999);
$dashboard->dividendsEarned = rand(-200, 3999);
return view('dashboard', compact('user', 'dashboard'));
}
}
@@ -20,6 +20,13 @@ class PortfolioController extends Controller
*/ */
public function show(Portfolio $portfolio) public function show(Portfolio $portfolio)
{ {
$portfolio->marketGainLoss = rand(-200, 3999);
$portfolio->totalCostBasis = rand(-200, 3999);
$portfolio->totalMarketValue = rand(-200, 3999);
$portfolio->realizedGainLoss = rand(-200, 3999);
$portfolio->dividendsEarned = rand(-200, 3999);
return view('portfolio.show', compact('portfolio')); return view('portfolio.show', compact('portfolio'));
} }
} }
@@ -73,92 +73,79 @@
$seriesData = json_encode($seriesData) $seriesData = json_encode($seriesData)
@endphp @endphp
<div <div
id="chart" id="chart"
wire:key="{{ rand() }}" wire:key="{{ rand() }}"
x-data="{ x-data="{
data: {{ $seriesData }}, data: {{ $seriesData }},
init(){ init(){
var charts = document.querySelectorAll('.apex-chart') this.data.chart.events = {
charts.forEach((chart)=>{ mounted: function (chartContext, config) {
console.log(chart) console.log('moount', chartContext)
}) renderCustomLegend(chartContext);
},
var existingChart = ApexCharts.getChartByID('{{ $name }}'); updated: function (chartContext, config) {
if (existingChart) { console.log('update')
console.log('found it') renderCustomLegend(chartContext);
existingChart.destroy();
} }
console.log('did not find')
this.data.chart.events = {
mounted: function (chartContext, config) {
console.log('moount', chartContext)
renderCustomLegend(chartContext);
},
updated: function (chartContext, config) {
console.log('update')
renderCustomLegend(chartContext);
}
}
var chart = new ApexCharts(document.querySelector('#chart-{{ $name }}'), this.data);
chart.render();
function renderCustomLegend(chartContext) {
var legendContainer = document.querySelector('#chart-legend-{{ $name }}');
if (!legendContainer) return;
legendContainer.innerHTML = ''; // Clear any existing legend items
chartContext.w.globals.seriesNames.forEach(function (seriesName, i) {
var seriesColor = chartContext.w.config.colors[i];
var legendItem = document.createElement('div');
legendItem.classList.add('flex', 'items-center', 'm-2', 'cursor-pointer');
legendItem.setAttribute('data-series-index', i);
var colorBox = document.createElement('span');
colorBox.id = seriesName
colorBox.classList.add('w-4', 'h-4', 'inline-block', 'mr-2');
colorBox.style.backgroundColor = seriesColor;
var labelText = document.createElement('span');
labelText.textContent = seriesName;
legendItem.appendChild(colorBox);
legendItem.appendChild(labelText);
legendContainer.appendChild(legendItem);
// Initial visibility state
var isCollapsed = chartContext.w.globals.collapsedSeriesIndices.includes(i);
if (isCollapsed) {
legendItem.classList.add('opacity-50');
}
legendItem.addEventListener('click', function () {
var seriesIndex = parseInt(this.getAttribute('data-series-index'), 10);
var isCurrentlyCollapsed = chartContext.w.globals.collapsedSeriesIndices.includes(seriesIndex);
chart.toggleSeries(chartContext.w.globals.seriesNames[seriesIndex]);
if (isCurrentlyCollapsed) {
this.classList.remove('opacity-50');
} else {
this.classList.add('opacity-50');
}
});
});
}
} }
}"
> var chart = new ApexCharts(document.querySelector('#chart-{{ $name }}'), this.data);
<div id="chart-{{ $name }}" class="apex-chart"></div>
</div> chart.render();
function renderCustomLegend(chartContext) {
var legendContainer = document.querySelector('#chart-legend-{{ $name }}');
if (!legendContainer) return;
legendContainer.innerHTML = ''; // Clear any existing legend items
chartContext.w.globals.seriesNames.forEach(function (seriesName, i) {
var seriesColor = chartContext.w.config.colors[i];
var legendItem = document.createElement('div');
legendItem.classList.add('flex', 'items-center', 'm-2', 'cursor-pointer');
legendItem.setAttribute('data-series-index', i);
var colorBox = document.createElement('span');
colorBox.id = seriesName
colorBox.classList.add('w-4', 'h-4', 'inline-block', 'mr-2');
colorBox.style.backgroundColor = seriesColor;
var labelText = document.createElement('span');
labelText.textContent = seriesName;
legendItem.appendChild(colorBox);
legendItem.appendChild(labelText);
legendContainer.appendChild(legendItem);
// Initial visibility state
var isCollapsed = chartContext.w.globals.collapsedSeriesIndices.includes(i);
if (isCollapsed) {
legendItem.classList.add('opacity-50');
}
legendItem.addEventListener('click', function () {
var seriesIndex = parseInt(this.getAttribute('data-series-index'), 10);
var isCurrentlyCollapsed = chartContext.w.globals.collapsedSeriesIndices.includes(seriesIndex);
chart.toggleSeries(chartContext.w.globals.seriesNames[seriesIndex]);
if (isCurrentlyCollapsed) {
this.classList.remove('opacity-50');
} else {
this.classList.add('opacity-50');
}
});
});
}
}
}"
>
<div id="chart-{{ $name }}" class="apex-chart"></div>
</div>
@@ -3,7 +3,15 @@
<x-menu-item title="{{ __('Dashboard') }}" icon="o-home" link="{{ @route('dashboard') }}" /> <x-menu-item title="{{ __('Dashboard') }}" icon="o-home" link="{{ @route('dashboard') }}" />
<x-menu-sub title="{{ __('Portfolios') }}" icon="o-document-duplicate"> <x-menu-sub title="{{ __('Portfolios') }}" icon="o-document-duplicate">
@foreach (auth()->user()->portfolios as $portfolio) @foreach (auth()->user()->portfolios as $portfolio)
<x-menu-item title="{{ $portfolio->title }}" icon="o-document" link="{{ route('portfolio.show', ['portfolio' => $portfolio->id ]) }}" /> <x-menu-item icon="o-document" link="{{ route('portfolio.show', ['portfolio' => $portfolio->id ]) }}" exact>
<x-slot:title>
{{ $portfolio->title }}
@if($portfolio->wishlist)
<x-badge value="{{ __('Wishlist') }}" class="badge-primary badge-sm ml-2" />
@endif
</x-slot:title>
</x-menu-item>
@endforeach @endforeach
<x-menu-item title="{{ __('Create Portfolio') }}" icon="o-document-plus" link="{{ @route('portfolio.create') }}" /> <x-menu-item title="{{ __('Create Portfolio') }}" icon="o-document-plus" link="{{ @route('portfolio.create') }}" />
+44 -47
View File
@@ -1,62 +1,59 @@
<x-app-layout> <x-app-layout>
<x-card class="bg-slate-100 dark:bg-base-200 rounded-lg mb-6"> @livewire('portfolio-performance-cards', [
'name' => 'dashboard'
])
@livewire('portfolio-performance-chart', [ <div class="grid sm:grid-cols-5 gap-5">
'name' => 'dashboard' @php
]) $formatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
@endphp
</x-card>
<div class="grid md:grid-cols-5 gap-5"> <x-card class="col-span-5 sm:col-span-1 bg-slate-100 dark:bg-base-200 rounded-lg">
<x-stat <div class="text-sm text-gray-400 whitespace-nowrap">{{ __('Market Gain/Loss') }}</div>
class="bg-slate-100 dark:bg-base-200" <div class="font-black text-xl"> {{ $formatter->formatCurrency($dashboard->marketGainLoss, 'USD') }} </div>
title="Market Gain/Loss" </x-card>
value="22.124"
icon="o-arrow-trending-up"
/>
<x-stat
class="bg-slate-100 dark:bg-base-200"
title="Total Cost Basis"
value="22.124"
icon="o-arrow-trending-up"
/>
<x-stat
class="bg-slate-100 dark:bg-base-200"
title="Total Market Value"
value="22.124"
icon="o-arrow-trending-up"
/>
<x-stat
class="bg-slate-100 dark:bg-base-200"
title="Realized Gain/Loss"
value="22.124"
icon="o-arrow-trending-up"
/>
<x-stat
class="bg-slate-100 dark:bg-base-200"
title="Dividends Earned"
value="22.124"
icon="o-arrow-trending-up"
/>
<x-card class="col-span-5 sm:col-span-1 bg-slate-100 dark:bg-base-200 rounded-lg">
<div class="text-sm text-gray-400 whitespace-nowrap">{{ __('Total Cost Basis') }}</div>
<div class="font-black text-xl"> {{ $formatter->formatCurrency($dashboard->totalCostBasis, 'USD') }} </div>
</x-card>
<x-card class="col-span-5 sm:col-span-1 bg-slate-100 dark:bg-base-200 rounded-lg">
<div class="text-sm text-gray-400 whitespace-nowrap">{{ __('Total Market Value') }}</div>
<div class="font-black text-xl"> {{ $formatter->formatCurrency($dashboard->totalMarketValue, 'USD') }} </div>
</x-card>
<x-card class="col-span-5 sm:col-span-1 bg-slate-100 dark:bg-base-200 rounded-lg">
<div class="text-sm text-gray-400 whitespace-nowrap">{{ __('Realized Gain/Loss') }}</div>
<div class="font-black text-xl"> {{ $formatter->formatCurrency($dashboard->realizedGainLoss, 'USD') }} </div>
</x-card>
<x-card class="col-span-5 sm:col-span-1 bg-slate-100 dark:bg-base-200 rounded-lg">
<div class="text-sm text-gray-400 whitespace-nowrap">{{ __('Dividends Earned') }}</div>
<div class="font-black text-xl"> {{ $formatter->formatCurrency($dashboard->dividendsEarned, 'USD') }} </div>
</x-card>
</div> </div>
<div class="mt-6 grid md:grid-cols-7 gap-5"> <div class="mt-6 grid md:grid-cols-7 gap-5">
<x-ib-card title="My portfolios" class="md:col-span-4"> <x-ib-card title="{{ __('My portfolios') }}" class="md:col-span-4">
@php
$users = App\Models\User::take(3)->get();
@endphp
@foreach($users as $user) @foreach($user->portfolios as $portfolio)
<x-list-item no-separator :item="$user" avatar="profile_photo_url" link="/docs/installation" /> <x-list-item no-separator :item="$portfolio" link="{{ route('portfolio.show', ['portfolio' => $portfolio->id]) }}">
<x-slot:value>
{{ $portfolio->title }}
@if($portfolio->wishlist)
<x-badge value="{{ __('Wishlist') }}" class="badge-primary badge-sm ml-2" />
@endif
</x-slot:value>
</x-list-item>
@endforeach @endforeach
</x-ib-card> </x-ib-card>
<x-ib-card title="Top performers" class="md:col-span-3"> <x-ib-card title="{{ __('Top performers') }}" class="md:col-span-3">
@php @php
$users = App\Models\User::take(3)->get(); $users = App\Models\User::take(3)->get();
@@ -68,7 +65,7 @@
</x-ib-card> </x-ib-card>
<x-ib-card title="Top headlines" class="md:col-span-3"> <x-ib-card title="{{ __('Top headlines') }}" class="md:col-span-3">
@php @php
$users = App\Models\User::take(3)->get(); $users = App\Models\User::take(3)->get();
@@ -80,7 +77,7 @@
</x-ib-card> </x-ib-card>
<x-ib-card title="Recent activity" class="md:col-span-4"> <x-ib-card title="{{ __('Recent activity') }}" class="md:col-span-4">
@php @php
$users = App\Models\User::take(3)->get(); $users = App\Models\User::take(3)->get();
@@ -42,7 +42,7 @@ new class extends Component {
// $this->portfolio->owner_id = auth()->user()->id; // $this->portfolio->owner_id = auth()->user()->id;
$this->portfolio->save(); $this->portfolio->save();
$this->success('Portfolio updated', redirectTo: "/portfolio/{$this->portfolio->id}"); $this->success(__('Portfolio updated'), redirectTo: "/portfolio/{$this->portfolio->id}");
} }
public function save() public function save()
@@ -65,7 +65,7 @@ new class extends Component {
// $portfolio->owner_id = auth()->user()->id; // $portfolio->owner_id = auth()->user()->id;
$portfolio->save(); $portfolio->save();
$this->success('Portfolio created', redirectTo: "/portfolio/{$portfolio->id}"); $this->success(__('Portfolio created'), redirectTo: "/portfolio/{$portfolio->id}");
} }
public function delete() public function delete()
@@ -73,17 +73,17 @@ new class extends Component {
$this->portfolio->delete(); $this->portfolio->delete();
$this->success('Portfolio deleted', redirectTo: "/dashboard"); $this->success(__('Portfolio deleted'), redirectTo: "/dashboard");
} }
}; ?> }; ?>
<div class="grid lg:grid-cols-4 gap-10"> <div class="grid lg:grid-cols-4 gap-10">
<x-form wire:submit="{{ $portfolio ? 'update' : 'save' }}" class="col-span-3"> <x-form wire:submit="{{ $portfolio ? 'update' : 'save' }}" class="col-span-3">
<x-input label="Title" wire:model="title" required /> <x-input label="{{ __('Title') }}" wire:model="title" required />
<x-textarea label="Notes" wire:model="notes" rows="5" /> <x-textarea label="{{ __('Notes') }}" wire:model="notes" rows="5" />
<x-toggle label="Wishlist" wire:model="wishlist" /> <x-toggle label="{{ __('Wishlist') }}" wire:model="wishlist" />
<x-slot:actions> <x-slot:actions>
@if ($portfolio) @if ($portfolio)
@@ -96,7 +96,7 @@ new class extends Component {
@endif @endif
@if (!$hideCancel) @if (!$hideCancel)
<x-button label="Cancel" link="/dashboard" /> <x-button label="{{ __('Cancel') }}" link="/dashboard" />
@endif @endif
<x-button label="{{ $portfolio ? 'Update' : 'Create' }}" type="submit" icon="o-paper-airplane" class="btn-primary" spinner="save" /> <x-button label="{{ $portfolio ? 'Update' : 'Create' }}" type="submit" icon="o-paper-airplane" class="btn-primary" spinner="save" />
</x-slot:actions> </x-slot:actions>
@@ -1,44 +0,0 @@
<?php
use App\Models\Portfolio;
use Livewire\Attributes\{Title, Rule};
use Livewire\Volt\Component;
new class extends Component {
// props
public ?Portfolio $portfolio;
public String $name = 'portfolio';
public String $scope = 'YTD';
public ?Int $value;
public Array $options = [
['id' => '1M', 'name' => '1 month'],
['id' => '3M', 'name' => '3 months'],
['id' => 'YTD', 'name' => 'Year to date'],
['id' => '1Y', 'name' => '1 year'],
['id' => '3Y', 'name' => '3 years'],
['id' => 'ALL', 'name' => 'All time']
];
protected $listeners = ['data-scope-updated' => 'test'];
public function test()
{
$this->value = 148;
}
// methods
public function mount()
{
//
}
}; ?>
<x-stat
class="bg-slate-100 dark:bg-base-200"
title="Market Gain/Loss"
:value="$value"
icon="o-arrow-trending-up"
/>
@@ -38,6 +38,8 @@ new class extends Component {
], ],
]; ];
// $this->marketGainLoss = rand(-200, 3999);
} }
public function changeScope($scope) public function changeScope($scope)
@@ -77,7 +79,7 @@ new class extends Component {
}; ?> }; ?>
<div> <x-card class="bg-slate-100 dark:bg-base-200 rounded-lg mb-6">
<div class="flex justify-between items-center mb-2"> <div class="flex justify-between items-center mb-2">
<div class="flex items-center"> <div class="flex items-center">
@@ -109,4 +111,4 @@ new class extends Component {
<x-ib-apex-chart :series-data="$myChart" :name="$name" /> <x-ib-apex-chart :series-data="$myChart" :name="$name" />
</div> </div>
</div> </x-card>
+33 -39
View File
@@ -27,50 +27,44 @@
/> />
</x-ib-toolbar> </x-ib-toolbar>
<x-card class="bg-slate-100 dark:bg-base-200 rounded-lg mb-6"> @livewire('portfolio-performance-cards', [
'name' => 'portfolio-'.$portfolio->id,
'portfolio' => $portfolio
])
@livewire('portfolio-performance-chart', [ <div class="grid sm:grid-cols-5 gap-5">
'name' => 'portfolio-'.$portfolio->id, @php
'portfolio' => $portfolio $formatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
]) @endphp
</x-card> <x-card class="col-span-5 sm:col-span-1 bg-slate-100 dark:bg-base-200 rounded-lg">
<div class="text-sm text-gray-400 whitespace-nowrap">{{ __('Market Gain/Loss') }}</div>
<div class="grid md:grid-cols-5 gap-5"> <div class="font-black text-xl"> {{ $formatter->formatCurrency($portfolio->marketGainLoss, 'USD') }} </div>
@livewire('portfolio-performance-card') </x-card>
{{-- <x-stat
class="bg-slate-100 dark:bg-base-200"
title="Market Gain/Loss"
value="22.124"
icon="o-arrow-trending-up"
/> --}}
<x-stat
class="bg-slate-100 dark:bg-base-200"
title="Total Cost Basis"
value="22.124"
icon="o-arrow-trending-up"
/>
<x-stat
class="bg-slate-100 dark:bg-base-200"
title="Total Market Value"
value="22.124"
icon="o-arrow-trending-up"
/>
<x-stat
class="bg-slate-100 dark:bg-base-200"
title="Realized Gain/Loss"
value="22.124"
icon="o-arrow-trending-up"
/>
<x-stat
class="bg-slate-100 dark:bg-base-200"
title="Dividends Earned"
value="22.124"
icon="o-arrow-trending-up"
/>
<x-card class="col-span-5 sm:col-span-1 bg-slate-100 dark:bg-base-200 rounded-lg">
<div class="text-sm text-gray-400 whitespace-nowrap">{{ __('Total Cost Basis') }}</div>
<div class="font-black text-xl"> {{ $formatter->formatCurrency($portfolio->totalCostBasis, 'USD') }} </div>
</x-card>
<x-card class="col-span-5 sm:col-span-1 bg-slate-100 dark:bg-base-200 rounded-lg">
<div class="text-sm text-gray-400 whitespace-nowrap">{{ __('Total Market Value') }}</div>
<div class="font-black text-xl"> {{ $formatter->formatCurrency($portfolio->totalMarketValue, 'USD') }} </div>
</x-card>
<x-card class="col-span-5 sm:col-span-1 bg-slate-100 dark:bg-base-200 rounded-lg">
<div class="text-sm text-gray-400 whitespace-nowrap">{{ __('Realized Gain/Loss') }}</div>
<div class="font-black text-xl"> {{ $formatter->formatCurrency($portfolio->realizedGainLoss, 'USD') }} </div>
</x-card>
<x-card class="col-span-5 sm:col-span-1 bg-slate-100 dark:bg-base-200 rounded-lg">
<div class="text-sm text-gray-400 whitespace-nowrap">{{ __('Dividends Earned') }}</div>
<div class="font-black text-xl"> {{ $formatter->formatCurrency($portfolio->dividendsEarned, 'USD') }} </div>
</x-card>
</div> </div>
<div class="mt-6 grid md:grid-cols-7 gap-5"> <div class="mt-6 grid md:grid-cols-7 gap-5">
<x-ib-card title="All portfolio holdings" class="md:col-span-4"> <x-ib-card title="All portfolio holdings" class="md:col-span-4">
+2 -1
View File
@@ -1,6 +1,7 @@
<?php <?php
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\PortfolioController; use App\Http\Controllers\PortfolioController;
Route::get('/', function () { Route::get('/', function () {
@@ -9,7 +10,7 @@ Route::get('/', function () {
Route::middleware(['auth:sanctum', config('jetstream.auth_session'), 'verified'])->group(function () { Route::middleware(['auth:sanctum', config('jetstream.auth_session'), 'verified'])->group(function () {
Route::view('/dashboard', 'dashboard')->name('dashboard'); Route::get('/dashboard', [DashboardController::class, 'show'])->name('dashboard');
Route::get('/portfolio/create', [PortfolioController::class, 'create'])->name('portfolio.create'); Route::get('/portfolio/create', [PortfolioController::class, 'create'])->name('portfolio.create');
Route::get('/portfolio/{portfolio}', [PortfolioController::class, 'show'])->name('portfolio.show'); Route::get('/portfolio/{portfolio}', [PortfolioController::class, 'show'])->name('portfolio.show');