359 lines
19 KiB
PHP
359 lines
19 KiB
PHP
<div class="relative mb-12 mt-0 w-full min-w-full leading-normal" id="single-report-component">
|
|
|
|
<!-- Decimal format toggle -->
|
|
@if($accountsData && $accountsData->count() > 0)
|
|
<div class="mb-6 flex items-center gap-3">
|
|
<x-toggle wire:model.live="decimalFormat" id="decimalFormatReport" name="decimalFormatReport" />
|
|
<span class="text-xs text-theme-light">{{ __('Show in decimals') }}</span>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Export buttons - always visible but disabled when no period selected -->
|
|
<div class="mb-8 mt-0 flex w-full justify-end">
|
|
<div class="space-x-2">
|
|
@if($this->fromDate && $this->toDate && $accountsData && $accountsData->count() > 0)
|
|
<x-jetstream.secondary-button wire:click="$dispatch('export-pdf-with-charts')" wire:loading.attr="disabled">
|
|
<span wire:loading.remove wire:target="handleExportPdfWithCharts">
|
|
<x-icon class="mr-1 h-4 w-4" name="arrow-down-tray" />
|
|
{{ __('PDF') }}
|
|
</span>
|
|
<span wire:loading wire:target="handleExportPdfWithCharts">
|
|
<x-icon class="mr-1 h-4 w-4 animate-spin" name="arrow-path" />
|
|
{{ __('Loading...') }}
|
|
</span>
|
|
</x-jetstream.secondary-button>
|
|
@else
|
|
<x-jetstream.secondary-button disabled class="cursor-not-allowed opacity-50">
|
|
<x-icon class="mr-1 h-4 w-4" name="arrow-down-tray" />
|
|
{{ __('PDF') }}
|
|
</x-jetstream.secondary-button>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
@if($accountsData && $accountsData->count() > 0)
|
|
<!-- Account Balances Table -->
|
|
<h3 class="text-lg font-medium text-theme-primary">
|
|
{{ __('Account Balance') }}
|
|
</h3>
|
|
<p class="text-sm text-theme-secondary mt-2">
|
|
{{ __('Balance overview of your accounts') }}
|
|
</p>
|
|
<div class="relative mb-24 w-full min-w-full leading-normal">
|
|
<table class="w-full" id="account-balances">
|
|
<thead>
|
|
<tr>
|
|
<th class="border-b border-theme-primary py-6 text-left">
|
|
<span class="px-0 py-2 text-sm font-normal text-theme-secondary">
|
|
{{ __('Account Name') }}
|
|
</span>
|
|
</th>
|
|
<th class="border-b border-theme-primary py-6 text-right">
|
|
<span class="px-0 py-2 text-sm font-normal text-theme-secondary">
|
|
{{ __('Start Balance') }}
|
|
</span>
|
|
</th>
|
|
<th class="border-b border-theme-primary py-6 text-right">
|
|
<span class="px-0 py-2 text-sm font-normal text-theme-secondary">
|
|
{{ __('End Balance') }}
|
|
</span>
|
|
</th>
|
|
<th class="border-b border-theme-primary py-6 text-right">
|
|
<span class="px-0 py-2 text-sm font-normal text-theme-secondary">
|
|
{{ __('Difference') }}
|
|
</span>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($accountsData as $account)
|
|
<tr>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-sm">
|
|
<div class="whitespace-no-wrap text-theme-primary font-medium">
|
|
{{ $account['name'] }}
|
|
</div>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-right text-sm">
|
|
<span class="whitespace-no-wrap text-theme-primary">
|
|
{{ $account['start_balance_formatted'] }}
|
|
</span>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-right text-sm">
|
|
<span class="whitespace-no-wrap text-theme-primary">
|
|
{{ $account['end_balance_formatted'] }}
|
|
</span>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-right text-sm">
|
|
<span class="whitespace-no-wrap @if($account['difference'] >= 0) text-theme-primary @else text-red-700 @endif">
|
|
{{ $account['difference_formatted'] }}@if($account['difference'] > 0) +@endif
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
|
|
<!-- Totals Row -->
|
|
<tr class="bg-gray-100">
|
|
<td class="border-b border-theme-primary bg-gray-100 px-2 py-3 text-sm">
|
|
<div class="whitespace-no-wrap text-theme-primary font-bold">
|
|
{{ __('TOTALS') }}
|
|
</div>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-gray-100 px-2 py-3 text-right text-sm">
|
|
<span class="whitespace-no-wrap text-theme-primary font-bold">
|
|
{{ $this->formatAmount($accountsData->sum('start_balance')) }}
|
|
</span>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-gray-100 px-2 py-3 text-right text-sm">
|
|
<span class="whitespace-no-wrap text-theme-primary font-bold">
|
|
{{ $this->formatAmount($accountsData->sum('end_balance')) }}
|
|
</span>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-gray-100 px-2 py-3 text-right text-sm">
|
|
@php $totalDifference = $accountsData->sum('difference'); @endphp
|
|
<span class="whitespace-no-wrap font-bold @if($totalDifference >= 0) text-theme-primary @else text-red-700 @endif">
|
|
{{ $this->formatAmount($totalDifference) }}@if($totalDifference > 0) +@endif
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Transaction Types Breakdown -->
|
|
@if($transactionTypesData && $transactionTypesData->count() > 0)
|
|
<div class="mb-6">
|
|
<h3 class="text-lg font-medium text-theme-primary">
|
|
{{ __('Transacion types') }}
|
|
</h3>
|
|
<p class="text-sm text-theme-secondary mt-2">
|
|
{{ __('Overview of the different transaction purposes') }}
|
|
</p>
|
|
</div>
|
|
<div class="relative mb-24 mt-12 w-full min-w-full leading-normal">
|
|
|
|
<table class="w-full text-left" id="transaction-types">
|
|
<thead>
|
|
<tr>
|
|
<th class="border-b border-theme-primary py-6">
|
|
<span class="px-0 py-2 text-sm font-normal text-theme-secondary">
|
|
{{ __('Transaction Type') }}
|
|
</span>
|
|
</th>
|
|
<th class="border-b border-theme-primary py-6 text-right">
|
|
<span class="px-0 py-2 text-sm font-normal text-theme-secondary">
|
|
{{ __('Credit') }}
|
|
</span>
|
|
</th>
|
|
<th class="border-b border-theme-primary py-6 text-right">
|
|
<span class="px-0 py-2 text-sm font-normal text-theme-secondary">
|
|
{{ __('Debit') }}
|
|
</span>
|
|
</th>
|
|
<th class="border-b border-theme-primary py-6 text-right">
|
|
<span class="px-0 py-2 text-sm font-normal text-theme-secondary">
|
|
{{ __('Total') }}
|
|
</span>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($transactionTypesData as $transactionType)
|
|
<tr>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-sm">
|
|
<div class="whitespace-no-wrap text-theme-primary">
|
|
{{ $transactionType['type_name'] }}
|
|
</div>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-right text-sm">
|
|
<span class="whitespace-no-wrap text-theme-primary">
|
|
{{ $transactionType['incoming_formatted'] }}
|
|
</span>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-right text-sm">
|
|
<span class="whitespace-no-wrap text-red-700">
|
|
{{ $transactionType['outgoing_formatted'] }}
|
|
</span>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-right text-sm">
|
|
<span class="whitespace-no-wrap @if($transactionType['net'] >= 0) text-theme-primary @else text-red-700 @endif">
|
|
{{ $transactionType['net_formatted'] }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Account Balances Chart -->
|
|
@if($accountBalancesTimelineData && count($accountBalancesTimelineData) > 4)
|
|
<div class="relative mb-24 mt-12 w-full min-w-full leading-normal">
|
|
<div class="mb-6">
|
|
<h3 class="text-lg font-medium text-theme-primary">
|
|
{{ __('Account Balance Over Time') }}
|
|
</h3>
|
|
<p class="text-sm text-theme-secondary mt-2">
|
|
{{ __('Track your account balance over time') }}
|
|
</p>
|
|
</div>
|
|
|
|
<div class="bg-white rounded-lg shadow-sm border border-theme-primary p-6"
|
|
data-balance-chart-data="{{ json_encode($accountBalancesTimelineData) }}"
|
|
data-decimal-format="{{ $decimalFormat ? '1' : '0' }}"
|
|
data-date-range="{{ $this->fromDate }} to {{ $this->toDate }}">
|
|
|
|
<canvas id="accountBalancesChart" width="400" height="200"></canvas>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
|
|
<!-- Return Ratio Timeline Chart -->
|
|
@if($isOrganization && $returnRatioTimelineData && count($returnRatioTimelineData) > 4)
|
|
<!-- Loading indicator positioned above chart -->
|
|
<div id="chartLoadingIndicator" class="flex items-center justify-center space-x-2 px-3 py-2 rounded-md mb-4" style="display: flex !important; visibility: visible !important;">
|
|
<div class="animate-spin rounded-full h-4 w-4 border-2 border-gray-300 border-t-gray-900"></div>
|
|
<span class="text-sm font-bold">
|
|
{{ __('Loading chart...') }}
|
|
</span>
|
|
</div>
|
|
<div class="relative mb-24 mt-12 w-full min-w-full leading-normal">
|
|
<div class="mb-6">
|
|
<h3 class="text-lg font-medium text-theme-primary">
|
|
{{ __('Reciprocity Rate Timeline') }}
|
|
</h3>
|
|
<p class="text-sm text-theme-secondary mt-2">
|
|
{{ __('Reciprocity rate: the share of your Hours that were also returned by the same people you helped during this period.') }}
|
|
</p>
|
|
<p class="text-sm text-theme-secondary mt-1">
|
|
{{ __('A high rate means you are part of a more closed exchange network with frequent returning exchange partners, while a low rate suggests you are part of a more open network with many different exchange partners.') }}
|
|
</p>
|
|
</div>
|
|
|
|
<div class="bg-white rounded-lg shadow-sm border border-theme-primary p-6"
|
|
data-chart-data="{{ json_encode($returnRatioTimelineData) }}"
|
|
data-trend-data="{{ json_encode($returnRatioTrendData) }}"
|
|
data-date-range="{{ $this->fromDate }} to {{ $this->toDate }}">
|
|
|
|
<canvas id="returnRatioChart" width="400" height="200"></canvas>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Period Statistics Table -->
|
|
<div class="">
|
|
<h3 class="text-lg font-medium text-theme-primary">
|
|
{{ __('Transaction Relation Statistics') }}
|
|
</h3>
|
|
<p class="text-sm text-theme-secondary mt-2">
|
|
{{ __('Which types of profiles have you transacted with?') }}
|
|
</p>
|
|
</div>
|
|
<div class="relative mb-12 w-full min-w-full leading-normal">
|
|
<table class="w-full" id="period-statistics">
|
|
<thead>
|
|
<tr>
|
|
<th class="border-b border-theme-primary text-left">
|
|
<span class="px-0 py-2 text-sm font-normal text-theme-secondary">
|
|
{{ __('Period Statistics') }}
|
|
</span>
|
|
</th>
|
|
<th class="border-b border-theme-primary py-6 text-right">
|
|
<span class="px-0 py-2 text-sm font-normal text-theme-secondary">
|
|
{{ __('Value') }}
|
|
</span>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-sm">
|
|
<div class="whitespace-no-wrap text-theme-primary">
|
|
{{ __('Number of Transactions') }}
|
|
</div>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-right text-sm">
|
|
<span class="whitespace-no-wrap text-theme-primary">
|
|
{{ number_format($statisticsData['transaction_count']) }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
@if($statisticsData['profiles_by_type'] && $statisticsData['profiles_by_type']->count() > 0)
|
|
@foreach($statisticsData['profiles_by_type'] as $modelType => $count)
|
|
<tr>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-sm">
|
|
<div class="whitespace-no-wrap text-theme-primary">
|
|
{{ __('Unique ' . class_basename($modelType) . 's') }}
|
|
</div>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-right text-sm">
|
|
<span class="whitespace-no-wrap text-theme-primary">
|
|
{{ number_format($count) }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
@endif
|
|
<tr>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-sm">
|
|
<div class="whitespace-no-wrap text-theme-primary">
|
|
{{ __('Total unique profiles') }}
|
|
</div>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-right text-sm">
|
|
<span class="whitespace-no-wrap text-theme-primary">
|
|
{{ number_format($statisticsData['unique_profiles']) }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
@if($isOrganization)
|
|
<tr>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-sm">
|
|
<div class="whitespace-no-wrap text-theme-primary">
|
|
{{ __('Average reciprocity rate') }}
|
|
</div>
|
|
</td>
|
|
<td class="border-b border-theme-primary bg-theme-background px-2 py-2 text-right text-sm">
|
|
<span class="whitespace-no-wrap text-theme-primary">
|
|
{{ number_format($statisticsData['average_return_ratio'], 1) }}%
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
@endif
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
@else
|
|
<div class="text-left py-8">
|
|
<div class="text-theme-secondary">
|
|
{{ __('Please select a period to generate the account balance report') }}
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<script>
|
|
// Register trigger-chart-export listener once globally (guard against re-registration on Livewire morphs)
|
|
if (!window._chartExportListenerRegistered) {
|
|
window._chartExportListenerRegistered = true;
|
|
|
|
function registerChartExportListener() {
|
|
Livewire.on('trigger-chart-export', () => {
|
|
if (typeof window.exportPdfWithChart === 'function') {
|
|
window.exportPdfWithChart();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Livewire may already be initialized (component renders after livewire:init fires)
|
|
if (typeof window.Livewire !== 'undefined') {
|
|
registerChartExportListener();
|
|
} else {
|
|
document.addEventListener('livewire:init', registerChartExportListener);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
</div>
|