|
|
@@ -4,10 +4,11 @@ namespace App\Http\Livewire;
|
|
|
|
|
|
use Livewire\Component;
|
|
|
use Carbon\Carbon;
|
|
|
+use Illuminate\Support\Facades\Log;
|
|
|
|
|
|
class Dashboard extends Component
|
|
|
{
|
|
|
-
|
|
|
+ // Existing properties
|
|
|
public $totMembers = 0;
|
|
|
public $totSuppliers = 0;
|
|
|
public $totTodayIn = 0;
|
|
|
@@ -16,165 +17,802 @@ class Dashboard extends Component
|
|
|
public $in;
|
|
|
public $out;
|
|
|
public $members;
|
|
|
+ public $activeUsers = 0;
|
|
|
+ public $registeredUsers = 0;
|
|
|
+ public $expiredCertificates = 0;
|
|
|
+ public $suspendedSubscriptions = 0;
|
|
|
+ public $activeUsersChange = 0;
|
|
|
+ public $registeredUsersChange = 0;
|
|
|
+ public $expiredCertificatesChange = 0;
|
|
|
+ public $suspendedSubscriptionsChange = 0;
|
|
|
+
|
|
|
+ public $toReceive = 0;
|
|
|
+ public $toPay = 0;
|
|
|
|
|
|
+ public $courses = [];
|
|
|
+ public $fields = [];
|
|
|
+ public $recentUsers = [];
|
|
|
+ public $recentTransactions = [];
|
|
|
+ public $coursesParticipation = [];
|
|
|
+ public $notes = '';
|
|
|
+ public $savedNotes = [];
|
|
|
public array $membersDatas = [];
|
|
|
public array $recordDatas = [];
|
|
|
public array $labels = [];
|
|
|
+ public array $monthlyLabels = [];
|
|
|
+ public array $monthlyIncomeData = [];
|
|
|
+ public array $monthlyExpenseData = [];
|
|
|
|
|
|
public function render()
|
|
|
{
|
|
|
+ Log::info('Dashboard render method called');
|
|
|
return view('livewire.dashboard');
|
|
|
}
|
|
|
|
|
|
public function mount()
|
|
|
{
|
|
|
+ Log::info('Dashboard mount started');
|
|
|
+ $startTime = microtime(true);
|
|
|
|
|
|
$this->dayName = Carbon::now()->locale('it_IT')->dayName;
|
|
|
+ Log::info('Day name set', ['day' => $this->dayName]);
|
|
|
+
|
|
|
+ $this->loadBasicStats();
|
|
|
+ $this->loadUserStats();
|
|
|
+ $this->loadFinancialStats();
|
|
|
+ $this->loadRecentData();
|
|
|
+ $this->loadSavedNotes();
|
|
|
+
|
|
|
+ $endTime = microtime(true);
|
|
|
+ $executionTime = round(($endTime - $startTime) * 1000, 2);
|
|
|
+ Log::info('Dashboard mount completed', [
|
|
|
+ 'execution_time_ms' => $executionTime,
|
|
|
+ 'active_users' => $this->activeUsers,
|
|
|
+ 'courses_count' => count($this->courses),
|
|
|
+ 'participation_count' => count($this->coursesParticipation)
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ private function loadBasicStats()
|
|
|
+ {
|
|
|
+ Log::info('Loading basic stats');
|
|
|
+ $startTime = microtime(true);
|
|
|
+
|
|
|
+ try {
|
|
|
+ $this->totMembers = \App\Models\Member::count();
|
|
|
+ $this->totSuppliers = \App\Models\Supplier::count();
|
|
|
+ Log::info('Basic counts loaded', [
|
|
|
+ 'total_members' => $this->totMembers,
|
|
|
+ 'total_suppliers' => $this->totSuppliers
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // Calculate today's income and expenses
|
|
|
+ $this->totTodayIn = 0;
|
|
|
+ $todayRecordsIn = \App\Models\Record::where('type', 'IN')
|
|
|
+ ->where('date', date("Y-m-d"))
|
|
|
+ ->get();
|
|
|
|
|
|
- $this->totMembers = \App\Models\Member::count();
|
|
|
- $this->totSuppliers = \App\Models\Supplier::count();
|
|
|
- $this->totTodayIn = 0;
|
|
|
- $tmp = \App\Models\Record::where('type', 'IN')->where('date', date("Y-m-d"))->get();
|
|
|
- foreach($tmp as $t)
|
|
|
- {
|
|
|
- foreach($t->rows as $r)
|
|
|
- {
|
|
|
- $this->totTodayIn += $r->amount;
|
|
|
+ foreach ($todayRecordsIn as $record) {
|
|
|
+ foreach ($record->rows as $row) {
|
|
|
+ $this->totTodayIn += $row->amount;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- //$this->totTodayIn = \App\Models\Record::where('type', 'IN')->where('date', date("Y-m-d"))->rows->sum('amount');
|
|
|
- $tmp = \App\Models\Record::where('type', 'OUT')->where('date', date("Y-m-d"))->get();
|
|
|
- foreach($tmp as $t)
|
|
|
- {
|
|
|
- foreach($t->rows as $r)
|
|
|
- {
|
|
|
- $this->totTodayOut += $r->amount;
|
|
|
+
|
|
|
+ $this->totTodayOut = 0;
|
|
|
+ $todayRecordsOut = \App\Models\Record::where('type', 'OUT')
|
|
|
+ ->where('date', date("Y-m-d"))
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ foreach ($todayRecordsOut as $record) {
|
|
|
+ foreach ($record->rows as $row) {
|
|
|
+ $this->totTodayOut += $row->amount;
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ $endTime = microtime(true);
|
|
|
+ Log::info('Basic stats loaded successfully', [
|
|
|
+ 'today_income' => $this->totTodayIn,
|
|
|
+ 'today_expenses' => $this->totTodayOut,
|
|
|
+ 'execution_time_ms' => round(($endTime - $startTime) * 1000, 2)
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error loading basic stats', [
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'file' => $e->getFile(),
|
|
|
+ 'line' => $e->getLine()
|
|
|
+ ]);
|
|
|
}
|
|
|
- //$this->totTodayOut = \App\Models\Record::where('type', 'OUT')->where('date', date("Y-m-d"))->rows->sum('amount');
|
|
|
+ }
|
|
|
|
|
|
- $this->members = \App\Models\Member::whereBetween('created_at', [date("y-m-d", strtotime('-7 days')), date("Y-m-d 23:59:59")])->select(\DB::raw("COUNT(*) as total, created_at"))->groupBy('created_at')->get();
|
|
|
+ private function loadUserStats()
|
|
|
+ {
|
|
|
+ Log::info('Loading user stats');
|
|
|
+ $startTime = microtime(true);
|
|
|
|
|
|
- $this->in = \App\Models\Record::where('type', 'IN')->whereBetween('date', [date("y-m-d", strtotime('-7 days')), date("Y-m-d 23:59:59")])->select(\DB::raw("SUM(amount) as total, date"))->groupBy('date')->get();
|
|
|
- $this->out = \App\Models\Record::where('type', 'OUT')->whereBetween('date', [date("y-m-d", strtotime('-7 days')), date("Y-m-d 23:59:59")])->select(\DB::raw("SUM(amount) as total, date"))->groupBy('date')->get();
|
|
|
+ try {
|
|
|
+ $this->activeUsers = \App\Models\Member::where('is_archived', 0)->orWhere('is_archived', NULL)->count();
|
|
|
+ $this->registeredUsers = \App\Models\Member::where('current_status', 2)->count();
|
|
|
+ $this->suspendedSubscriptions = \App\Models\Member::where('current_status', 1)->count();
|
|
|
|
|
|
- $this->labels = $this->getLabels();
|
|
|
+ Log::info('User counts loaded', [
|
|
|
+ 'active_users' => $this->activeUsers,
|
|
|
+ 'registered_users' => $this->registeredUsers,
|
|
|
+ 'suspended_subscriptions' => $this->suspendedSubscriptions
|
|
|
+ ]);
|
|
|
|
|
|
- $this->memberDatas = [
|
|
|
- [
|
|
|
- 'label' => 'Utenti',
|
|
|
- 'backgroundColor' => 'blue',
|
|
|
- 'borderColor' => 'blue',
|
|
|
- // 'data' => $this->getRandomData(),
|
|
|
- 'data' => $this->getMemberData(),
|
|
|
- ]
|
|
|
- ];
|
|
|
+ $this->expiredCertificates = \App\Models\Member::whereHas('certificates', function ($query) {
|
|
|
+ $query->where('expire_date', '<', now());
|
|
|
+ })->whereDoesntHave('certificates', function ($query) {
|
|
|
+ $query->where('expire_date', '>=', now());
|
|
|
+ })->count();
|
|
|
|
|
|
- $this->recordDatas = [
|
|
|
- [
|
|
|
- 'label' => 'Entrate',
|
|
|
- 'backgroundColor' => 'green',
|
|
|
- 'borderColor' => 'green',
|
|
|
- // 'data' => $this->getRandomData(),
|
|
|
- 'data' => $this->getRecordData('IN'),
|
|
|
- ],
|
|
|
- [
|
|
|
- 'label' => 'Uscite',
|
|
|
- 'backgroundColor' => 'red',
|
|
|
- 'borderColor' => 'red',
|
|
|
- 'data' => $this->getRecordData('OUT'),
|
|
|
- ]
|
|
|
- ];
|
|
|
+ Log::info('Expired certificates count', ['expired_certificates' => $this->expiredCertificates]);
|
|
|
+
|
|
|
+ // Calculate changes from last month
|
|
|
+ $lastMonth = now()->subMonth();
|
|
|
+ $endOfLastMonth = $lastMonth->copy()->endOfMonth();
|
|
|
+
|
|
|
+ $lastMonthActiveUsers = \App\Models\Member::where('is_archived', false)
|
|
|
+ ->where('created_at', '<=', $endOfLastMonth)
|
|
|
+ ->count();
|
|
|
+ $lastMonthRegisteredUsers = \App\Models\Member::where('current_status', 2)
|
|
|
+ ->where('updated_at', '<=', $endOfLastMonth)
|
|
|
+ ->count();
|
|
|
+ $lastMonthSuspendedSubscriptions = \App\Models\Member::where('current_status', 1)
|
|
|
+ ->where('updated_at', '<=', $endOfLastMonth)
|
|
|
+ ->count();
|
|
|
+ $lastMonthExpiredCertificates = \App\Models\Member::whereHas('certificates', function ($query) use ($endOfLastMonth) {
|
|
|
+ $query->where('expire_date', '<', $endOfLastMonth);
|
|
|
+ })->whereDoesntHave('certificates', function ($query) use ($endOfLastMonth) {
|
|
|
+ $query->where('expire_date', '>=', $endOfLastMonth);
|
|
|
+ })->count();
|
|
|
+
|
|
|
+ $this->activeUsersChange = $this->activeUsers - $lastMonthActiveUsers;
|
|
|
+ $this->registeredUsersChange = $this->registeredUsers - $lastMonthRegisteredUsers;
|
|
|
+ $this->expiredCertificatesChange = $this->expiredCertificates - $lastMonthExpiredCertificates;
|
|
|
+ $this->suspendedSubscriptionsChange = $this->suspendedSubscriptions - $lastMonthSuspendedSubscriptions;
|
|
|
+
|
|
|
+ $endTime = microtime(true);
|
|
|
+ Log::info('User stats loaded successfully', [
|
|
|
+ 'changes' => [
|
|
|
+ 'active_users' => $this->activeUsersChange,
|
|
|
+ 'registered_users' => $this->registeredUsersChange,
|
|
|
+ 'expired_certificates' => $this->expiredCertificatesChange,
|
|
|
+ 'suspended_subscriptions' => $this->suspendedSubscriptionsChange
|
|
|
+ ],
|
|
|
+ 'execution_time_ms' => round(($endTime - $startTime) * 1000, 2)
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error loading user stats', [
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'file' => $e->getFile(),
|
|
|
+ 'line' => $e->getLine()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private function getLabels()
|
|
|
+ private function loadFinancialStats()
|
|
|
{
|
|
|
- $labels = array();
|
|
|
- for($i=0; $i<=7; $i++)
|
|
|
- {
|
|
|
- $labels[] = date("d/M", strtotime('-' . $i . ' days'));
|
|
|
+ Log::info('Loading financial stats');
|
|
|
+ $startTime = microtime(true);
|
|
|
+
|
|
|
+ try {
|
|
|
+ $currentMonth = now()->format('Y-m');
|
|
|
+ Log::info('Calculating financial stats for month', ['month' => $currentMonth]);
|
|
|
+
|
|
|
+ $this->toReceive = \App\Models\Record::where('type', 'IN')
|
|
|
+ ->whereRaw('DATE_FORMAT(date, "%Y-%m") = ?', [$currentMonth])
|
|
|
+ ->where(function ($query) {
|
|
|
+ $query->where('deleted', false)->orWhere('deleted', null);
|
|
|
+ })
|
|
|
+ ->sum('amount') ?? 0;
|
|
|
+
|
|
|
+ $this->toPay = \App\Models\Record::where('type', 'OUT')
|
|
|
+ ->whereRaw('DATE_FORMAT(date, "%Y-%m") = ?', [$currentMonth])
|
|
|
+ ->where(function ($query) {
|
|
|
+ $query->where('deleted', false)->orWhere('deleted', null);
|
|
|
+ })
|
|
|
+ ->sum('amount') ?? 0;
|
|
|
+
|
|
|
+ $endTime = microtime(true);
|
|
|
+ Log::info('Financial stats loaded successfully', [
|
|
|
+ 'to_receive' => $this->toReceive,
|
|
|
+ 'to_pay' => $this->toPay,
|
|
|
+ 'execution_time_ms' => round(($endTime - $startTime) * 1000, 2)
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error loading financial stats', [
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'file' => $e->getFile(),
|
|
|
+ 'line' => $e->getLine()
|
|
|
+ ]);
|
|
|
}
|
|
|
- return array_reverse($labels);
|
|
|
}
|
|
|
|
|
|
- private function getRecordData($type)
|
|
|
+ private function loadRecentData()
|
|
|
{
|
|
|
- $data = [];
|
|
|
- for($i=0; $i<=7; $i++)
|
|
|
- {
|
|
|
- if ($type == 'IN')
|
|
|
- {
|
|
|
- $found = false;
|
|
|
- foreach($this->in as $in)
|
|
|
- {
|
|
|
- if (date("Y-m-d", strtotime($in->date)) == date("Y-m-d", strtotime('-' . $i . ' days')))
|
|
|
- {
|
|
|
- $data[] = $in->total;
|
|
|
- $found = true;
|
|
|
+ Log::info('Loading recent data');
|
|
|
+ $startTime = microtime(true);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // Load recent users
|
|
|
+ $recentMembers = \App\Models\Member::where('is_archived', 0)
|
|
|
+ ->orWhere('is_archived', NULL)
|
|
|
+ ->orderBy('created_at', 'desc')
|
|
|
+ ->limit(5)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ $this->recentUsers = $recentMembers->map(function ($member) {
|
|
|
+ return [
|
|
|
+ 'surname' => strtoupper($member->last_name),
|
|
|
+ 'name' => strtoupper($member->first_name),
|
|
|
+ 'phone' => $member->phone ?? '',
|
|
|
+ 'email' => $member->email ?? ''
|
|
|
+ ];
|
|
|
+ })->toArray();
|
|
|
+
|
|
|
+ Log::info('Recent users loaded', ['count' => count($this->recentUsers)]);
|
|
|
+
|
|
|
+ // Load recent transactions
|
|
|
+ $recentRecords = \App\Models\Record::where('date', '>=', now()->subDays(30))
|
|
|
+ ->with(['member', 'supplier'])
|
|
|
+ ->orderBy('date', 'desc')
|
|
|
+ ->orderBy('created_at', 'desc')
|
|
|
+ ->limit(10)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ $this->recentTransactions = $recentRecords->map(function ($record) {
|
|
|
+ if ($record->type == 'IN') {
|
|
|
+ $name = $record->member ?
|
|
|
+ strtoupper($record->member->last_name) . ' ' . strtoupper($record->member->first_name) :
|
|
|
+ 'MEMBRO SCONOSCIUTO';
|
|
|
+ } else {
|
|
|
+ $name = $record->supplier ?
|
|
|
+ strtoupper($record->supplier->name) :
|
|
|
+ 'FORNITORE SCONOSCIUTO';
|
|
|
+ }
|
|
|
+
|
|
|
+ $totalAmount = 0;
|
|
|
+ foreach ($record->rows as $row) {
|
|
|
+ $totalAmount += $row->amount;
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'name' => $name,
|
|
|
+ 'amount' => $totalAmount,
|
|
|
+ 'type' => $record->type == 'IN' ? 'ENTRATA' : 'USCITA'
|
|
|
+ ];
|
|
|
+ })->toArray();
|
|
|
+
|
|
|
+ Log::info('Recent transactions loaded', ['count' => count($this->recentTransactions)]);
|
|
|
+
|
|
|
+ $this->loadCoursesData();
|
|
|
+ $this->loadCoursesParticipation();
|
|
|
+
|
|
|
+ $endTime = microtime(true);
|
|
|
+ Log::info('Recent data loaded successfully', [
|
|
|
+ 'execution_time_ms' => round(($endTime - $startTime) * 1000, 2)
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error loading recent data', [
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'file' => $e->getFile(),
|
|
|
+ 'line' => $e->getLine()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private function loadCoursesData()
|
|
|
+ {
|
|
|
+ Log::info('Loading courses data');
|
|
|
+ $startTime = microtime(true);
|
|
|
+
|
|
|
+ try {
|
|
|
+ $today = now()->format('N');
|
|
|
+ $dayNames = [
|
|
|
+ 1 => 'lun',
|
|
|
+ 2 => 'mar',
|
|
|
+ 3 => 'mer',
|
|
|
+ 4 => 'gio',
|
|
|
+ 5 => 'ven',
|
|
|
+ 6 => 'sab',
|
|
|
+ 7 => 'dom'
|
|
|
+ ];
|
|
|
+ $todayName = $dayNames[$today];
|
|
|
+
|
|
|
+ Log::info('Searching courses for today', [
|
|
|
+ 'today_number' => $today,
|
|
|
+ 'today_name' => $todayName
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $memberCourses = \App\Models\MemberCourse::with(['course.level', 'course.frequency', 'member'])
|
|
|
+ ->whereIn('status', [0, 1])
|
|
|
+ ->whereHas('course', function ($query) {
|
|
|
+ $query->whereNotNull('when');
|
|
|
+ })
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ Log::info('Total member courses found', [
|
|
|
+ 'count' => $memberCourses->count()
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $activeCourses = $memberCourses->filter(function ($memberCourse) use ($todayName) {
|
|
|
+ try {
|
|
|
+ $whenData = json_decode($memberCourse->course->when, true);
|
|
|
+
|
|
|
+ if (!is_array($whenData)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($whenData as $schedule) {
|
|
|
+ if (
|
|
|
+ isset($schedule['day']) &&
|
|
|
+ is_array($schedule['day']) &&
|
|
|
+ in_array($todayName, $schedule['day'])
|
|
|
+ ) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
}
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::debug('Error parsing course schedule', [
|
|
|
+ 'member_course_id' => $memberCourse->id,
|
|
|
+ 'course_id' => $memberCourse->course->id,
|
|
|
+ 'when' => $memberCourse->course->when,
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ]);
|
|
|
}
|
|
|
- if (!$found)
|
|
|
- $data[] = 0;
|
|
|
- }
|
|
|
- if ($type == 'OUT')
|
|
|
- {
|
|
|
- $found = false;
|
|
|
- foreach($this->out as $out)
|
|
|
- {
|
|
|
- if (date("Y-m-d", strtotime($out->date)) == date("Y-m-d", strtotime('-' . $i . ' days')))
|
|
|
- {
|
|
|
- $data[] = $out->total;
|
|
|
- $found = true;
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+
|
|
|
+ Log::info('Active courses found for today', [
|
|
|
+ 'count' => $activeCourses->count(),
|
|
|
+ 'course_ids' => $activeCourses->pluck('course.id')->toArray()
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $this->courses = $activeCourses->map(function ($memberCourse) use ($todayName) {
|
|
|
+ $whenData = json_decode($memberCourse->course->when, true);
|
|
|
+
|
|
|
+ Log::debug('Processing course schedule', [
|
|
|
+ 'member_course_id' => $memberCourse->id,
|
|
|
+ 'course_id' => $memberCourse->course->id,
|
|
|
+ 'course_name' => $memberCourse->course->name,
|
|
|
+ 'when_data' => $whenData,
|
|
|
+ 'looking_for_day' => $todayName
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $todaySchedule = null;
|
|
|
+
|
|
|
+ if (is_array($whenData)) {
|
|
|
+ foreach ($whenData as $schedule) {
|
|
|
+ if (
|
|
|
+ isset($schedule['day']) &&
|
|
|
+ is_array($schedule['day']) &&
|
|
|
+ in_array($todayName, $schedule['day'])
|
|
|
+ ) {
|
|
|
+ $todaySchedule = $schedule;
|
|
|
+ Log::debug('Found matching schedule', [
|
|
|
+ 'schedule' => $schedule,
|
|
|
+ 'course_id' => $memberCourse->course->id
|
|
|
+ ]);
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- if (!$found)
|
|
|
- $data[] = 0;
|
|
|
- }
|
|
|
+
|
|
|
+ if (!$todaySchedule) {
|
|
|
+ Log::debug('No matching schedule found for today', [
|
|
|
+ 'course_id' => $memberCourse->course->id,
|
|
|
+ 'when_data' => $whenData
|
|
|
+ ]);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ $days = implode('-', array_map('ucfirst', $todaySchedule['day']));
|
|
|
+ $course = $memberCourse->course;
|
|
|
+
|
|
|
+ $courseName = $course->name ?? 'Corso Sconosciuto';
|
|
|
+ $levelName = $course->level?->name ?? '';
|
|
|
+ $frequencyName = $course->frequency?->name ?? '';
|
|
|
+ $typeName = $course->getFormattedTypeField() ?? '';
|
|
|
+
|
|
|
+ $courseNameParts = [$courseName];
|
|
|
+ if ($levelName) $courseNameParts[] = $levelName;
|
|
|
+ if ($typeName) $courseNameParts[] = $typeName;
|
|
|
+ if ($frequencyName) $courseNameParts[] = $frequencyName;
|
|
|
+
|
|
|
+ $fullCourseName = implode(' - ', $courseNameParts);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'time' => $todaySchedule['from'] . ' - ' . $todaySchedule['to'],
|
|
|
+ 'course_name' => $courseName,
|
|
|
+ 'full_name' => $fullCourseName,
|
|
|
+ 'level_name' => $levelName,
|
|
|
+ 'type_name' => $typeName,
|
|
|
+ 'frequency_name' => $frequencyName,
|
|
|
+ 'days' => $days,
|
|
|
+ 'type' => $course->type ?? 'Standard',
|
|
|
+ 'from_time' => $todaySchedule['from'],
|
|
|
+ 'course_id' => $course->id,
|
|
|
+ 'member_course_id' => $memberCourse->id
|
|
|
+ ];
|
|
|
+ })->filter()->values();
|
|
|
+
|
|
|
+ $sortedCourses = $this->courses->sortBy('from_time')->take(5);
|
|
|
+
|
|
|
+ Log::info('Courses sorted by time', [
|
|
|
+ 'sorted_courses' => $sortedCourses->map(function ($course) {
|
|
|
+ return [
|
|
|
+ 'time' => $course['time'],
|
|
|
+ 'from_time' => $course['from_time'],
|
|
|
+ 'course_name' => $course['course_name'],
|
|
|
+ 'course_id' => $course['course_id']
|
|
|
+ ];
|
|
|
+ })->toArray()
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $this->courses = $sortedCourses->map(function ($course) {
|
|
|
+ unset($course['from_time'], $course['member_course_id'], $course['course_id']);
|
|
|
+ return $course;
|
|
|
+ })->toArray();
|
|
|
+
|
|
|
+ $endTime = microtime(true);
|
|
|
+ Log::info('Courses data loaded successfully', [
|
|
|
+ 'final_courses_count' => count($this->courses),
|
|
|
+ 'execution_time_ms' => round(($endTime - $startTime) * 1000, 2),
|
|
|
+ 'final_courses_display' => $this->courses
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error loading courses data', [
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'file' => $e->getFile(),
|
|
|
+ 'line' => $e->getLine()
|
|
|
+ ]);
|
|
|
+ $this->courses = [];
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ private function loadCoursesParticipation()
|
|
|
+ {
|
|
|
+ Log::info('Loading courses participation');
|
|
|
+ $startTime = microtime(true);
|
|
|
|
|
|
- return array_reverse($data);
|
|
|
+ try {
|
|
|
+ // Conta le partecipazioni per corso (include tutti gli status)
|
|
|
+ $courseStats = \App\Models\MemberCourse::with(['course.level', 'course.frequency'])
|
|
|
+ ->whereIn('status', [0, 1]) // Include both statuses
|
|
|
+ ->selectRaw('course_id, COUNT(*) as participants')
|
|
|
+ ->groupBy('course_id')
|
|
|
+ ->orderBy('participants', 'desc')
|
|
|
+ ->limit(4)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ Log::info('Course participation stats', [
|
|
|
+ 'courses_found' => $courseStats->count(),
|
|
|
+ 'stats' => $courseStats->map(function ($stat) {
|
|
|
+ $course = $stat->course;
|
|
|
+ $levelName = is_object($course->level) ? $course->level->name : '';
|
|
|
+ $frequencyName = is_object($course->frequency) ? $course->frequency->name : '';
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'course_id' => $stat->course_id,
|
|
|
+ 'course_name' => $course->name ?? 'Unknown',
|
|
|
+ 'level_name' => $levelName,
|
|
|
+ 'frequency_name' => $frequencyName,
|
|
|
+ 'participants' => $stat->participants
|
|
|
+ ];
|
|
|
+ })->toArray()
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $totalParticipants = $courseStats->sum('participants');
|
|
|
+
|
|
|
+ $this->coursesParticipation = $courseStats->map(function ($stat) use ($totalParticipants) {
|
|
|
+ $percentage = $totalParticipants > 0 ? ($stat->participants / $totalParticipants) * 100 : 0;
|
|
|
+ $course = $stat->course;
|
|
|
+ $courseName = $course->name ?? 'Corso Sconosciuto';
|
|
|
+ $levelName = is_object($course->level) ? $course->level->name : '';
|
|
|
+ $frequencyName = is_object($course->frequency) ? $course->frequency->name : '';
|
|
|
+ $typeName = $course->getFormattedTypeField() ?? '';
|
|
|
+
|
|
|
+ // Build display name with level and frequency
|
|
|
+ $displayNameParts = [$courseName];
|
|
|
+ if ($levelName) $displayNameParts[] = $levelName;
|
|
|
+ if ($typeName) $displayNameParts[] = $typeName;
|
|
|
+ if ($frequencyName) $displayNameParts[] = $frequencyName;
|
|
|
+
|
|
|
+ $displayName = implode(' - ', $displayNameParts);
|
|
|
+
|
|
|
+ // Assegna colori basati sul nome del corso
|
|
|
+ $color = $this->getCourseColor($courseName);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'course_name' => $displayName,
|
|
|
+ 'base_course_name' => $courseName,
|
|
|
+ 'level_name' => $levelName,
|
|
|
+ 'type_name' => $typeName,
|
|
|
+ 'frequency_name' => $frequencyName,
|
|
|
+ 'participants' => $stat->participants,
|
|
|
+ 'percentage' => round($percentage, 1),
|
|
|
+ 'color' => $color
|
|
|
+ ];
|
|
|
+ })->toArray();
|
|
|
+
|
|
|
+ $endTime = microtime(true);
|
|
|
+ Log::info('Courses participation loaded successfully', [
|
|
|
+ 'total_participants' => $totalParticipants,
|
|
|
+ 'participation_data' => $this->coursesParticipation,
|
|
|
+ 'execution_time_ms' => round(($endTime - $startTime) * 1000, 2)
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error loading courses participation', [
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'file' => $e->getFile(),
|
|
|
+ 'line' => $e->getLine()
|
|
|
+ ]);
|
|
|
+ $this->coursesParticipation = [];
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private function getMemberData()
|
|
|
+ private function getCourseColor($courseName)
|
|
|
{
|
|
|
- $data = [];
|
|
|
- for($i=0; $i<=7; $i++)
|
|
|
- {
|
|
|
- $found = false;
|
|
|
- foreach($this->members as $member)
|
|
|
- {
|
|
|
- if (date("Y-m-d", strtotime($member->created_at)) == date("Y-m-d", strtotime('-' . $i . ' days')))
|
|
|
- {
|
|
|
- $data[] = $member->total;
|
|
|
- $found = true;
|
|
|
- }
|
|
|
- }
|
|
|
- if (!$found)
|
|
|
- $data[] = 0;
|
|
|
+ $colors = [
|
|
|
+ 'padel',
|
|
|
+ 'tennis',
|
|
|
+ 'pallavolo',
|
|
|
+ 'yoga',
|
|
|
+ 'blue',
|
|
|
+ 'pink',
|
|
|
+ 'green',
|
|
|
+ 'red',
|
|
|
+ 'indigo',
|
|
|
+ 'amber',
|
|
|
+ 'cyan',
|
|
|
+ 'lime'
|
|
|
+ ];
|
|
|
+ $hash = crc32($courseName);
|
|
|
+ $colorIndex = abs($hash) % count($colors);
|
|
|
+ $assignedColor = $colors[$colorIndex];
|
|
|
+
|
|
|
+ Log::debug('Course color assigned', [
|
|
|
+ 'course_name' => $courseName,
|
|
|
+ 'hash' => $hash,
|
|
|
+ 'color_index' => $colorIndex,
|
|
|
+ 'assigned_color' => $assignedColor
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return $assignedColor;
|
|
|
+ }
|
|
|
+
|
|
|
+ private function loadSavedNotes()
|
|
|
+ {
|
|
|
+ Log::info('Loading saved notes');
|
|
|
+
|
|
|
+ try {
|
|
|
+ $this->savedNotes = session()->get('dashboard_notes', []);
|
|
|
+
|
|
|
+ Log::info('Saved notes loaded', [
|
|
|
+ 'notes_count' => count($this->savedNotes)
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error loading saved notes', [
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ]);
|
|
|
+ $this->savedNotes = [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private function saveSavedNotes()
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ session()->put('dashboard_notes', $this->savedNotes);
|
|
|
+
|
|
|
+ Log::info('Notes saved to session', [
|
|
|
+ 'notes_count' => count($this->savedNotes)
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error saving notes', [
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ public function saveNote()
|
|
|
+ {
|
|
|
+ Log::info('Save note called', ['note_text' => $this->notes]);
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (trim($this->notes) !== '') {
|
|
|
+ $newNote = [
|
|
|
+ 'id' => uniqid(),
|
|
|
+ 'text' => trim($this->notes),
|
|
|
+ 'created_at' => now()->format('d/m/Y H:i'),
|
|
|
+ 'completed' => false
|
|
|
+ ];
|
|
|
+
|
|
|
+ array_unshift($this->savedNotes, $newNote);
|
|
|
+
|
|
|
+ $this->saveSavedNotes();
|
|
|
+
|
|
|
+ $this->notes = '';
|
|
|
+
|
|
|
+ $this->dispatchBrowserEvent('note-saved');
|
|
|
+
|
|
|
+ Log::info('Note saved successfully', [
|
|
|
+ 'note_id' => $newNote['id'],
|
|
|
+ 'total_notes' => count($this->savedNotes)
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ Log::warning('Attempted to save empty note');
|
|
|
+ }
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error saving note', [
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'file' => $e->getFile(),
|
|
|
+ 'line' => $e->getLine()
|
|
|
+ ]);
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ public function completeNote($noteId)
|
|
|
+ {
|
|
|
+ Log::info('Complete note called', ['note_id' => $noteId]);
|
|
|
|
|
|
- return array_reverse($data);
|
|
|
+ try {
|
|
|
+ $initialCount = count($this->savedNotes);
|
|
|
+
|
|
|
+ $this->savedNotes = array_filter($this->savedNotes, function ($note) use ($noteId) {
|
|
|
+ return $note['id'] !== $noteId;
|
|
|
+ });
|
|
|
+
|
|
|
+ $this->savedNotes = array_values($this->savedNotes);
|
|
|
+
|
|
|
+ $finalCount = count($this->savedNotes);
|
|
|
+
|
|
|
+ if ($initialCount > $finalCount) {
|
|
|
+ $this->saveSavedNotes();
|
|
|
+
|
|
|
+ $this->dispatchBrowserEvent('note-completed');
|
|
|
+
|
|
|
+ Log::info('Note completed successfully', [
|
|
|
+ 'note_id' => $noteId,
|
|
|
+ 'remaining_notes' => $finalCount
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ Log::warning('Note not found for completion', ['note_id' => $noteId]);
|
|
|
+ }
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error completing note', [
|
|
|
+ 'note_id' => $noteId,
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'file' => $e->getFile(),
|
|
|
+ 'line' => $e->getLine()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public function addMember()
|
|
|
{
|
|
|
+ Log::info('Redirecting to add member');
|
|
|
return redirect()->to('/members?new=1');
|
|
|
}
|
|
|
|
|
|
public function addSupplier()
|
|
|
{
|
|
|
+ Log::info('Redirecting to add supplier');
|
|
|
return redirect()->to('/suppliers?new=1');
|
|
|
}
|
|
|
|
|
|
public function addIn()
|
|
|
{
|
|
|
+ Log::info('Redirecting to add income record');
|
|
|
return redirect()->to('/in?new=1');
|
|
|
}
|
|
|
|
|
|
public function addOut()
|
|
|
{
|
|
|
+ Log::info('Redirecting to add expense record');
|
|
|
return redirect()->to('/out?new=1');
|
|
|
}
|
|
|
|
|
|
+ public function debugCourses()
|
|
|
+ {
|
|
|
+ Log::info('=== DEBUG COURSES CALLED ===');
|
|
|
+
|
|
|
+ $today = now()->format('N');
|
|
|
+ $dayNames = [
|
|
|
+ 1 => 'lun',
|
|
|
+ 2 => 'mar',
|
|
|
+ 3 => 'mer',
|
|
|
+ 4 => 'gio',
|
|
|
+ 5 => 'ven',
|
|
|
+ 6 => 'sab',
|
|
|
+ 7 => 'dom'
|
|
|
+ ];
|
|
|
+ $todayName = $dayNames[$today];
|
|
|
+
|
|
|
+ // Get all member courses
|
|
|
+ $allCourses = \App\Models\MemberCourse::with('course')->get();
|
|
|
+
|
|
|
+ Log::info('All courses debug', [
|
|
|
+ 'total_courses' => $allCourses->count(),
|
|
|
+ 'today_name' => $todayName,
|
|
|
+ 'courses' => $allCourses->map(function ($mc) {
|
|
|
+ return [
|
|
|
+ 'id' => $mc->id,
|
|
|
+ 'status' => $mc->status,
|
|
|
+ 'when' => $mc->when,
|
|
|
+ 'course_name' => $mc->course->name ?? 'Unknown'
|
|
|
+ ];
|
|
|
+ })->toArray()
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $this->dispatchBrowserEvent('debug-completed');
|
|
|
+ }
|
|
|
+
|
|
|
+ public function activateTestCourses()
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ $updated = \App\Models\MemberCourse::whereIn('id', [21, 22, 23, 24])
|
|
|
+ ->update(['status' => 1]);
|
|
|
+
|
|
|
+ Log::info('Activated test courses', ['updated_count' => $updated]);
|
|
|
+
|
|
|
+ $this->loadCoursesData();
|
|
|
+ $this->loadCoursesParticipation();
|
|
|
+
|
|
|
+ $this->dispatchBrowserEvent('courses-activated', [
|
|
|
+ 'message' => "Attivati $updated corsi per test"
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('Error activating courses', ['error' => $e->getMessage()]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private function getLabels()
|
|
|
+ {
|
|
|
+ $labels = array();
|
|
|
+ for ($i = 6; $i >= 0; $i--) {
|
|
|
+ $labels[] = date("d/M", strtotime('-' . $i . ' days'));
|
|
|
+ }
|
|
|
+ return $labels;
|
|
|
+ }
|
|
|
+
|
|
|
+ private function getRecordData($type)
|
|
|
+ {
|
|
|
+ $data = [];
|
|
|
+ for ($i = 6; $i >= 0; $i--) {
|
|
|
+ $found = false;
|
|
|
+ $records = $type == 'IN' ? $this->in : $this->out;
|
|
|
+
|
|
|
+ foreach ($records as $record) {
|
|
|
+ if (date("Y-m-d", strtotime($record->date)) == date("Y-m-d", strtotime('-' . $i . ' days'))) {
|
|
|
+ $data[] = $record->total;
|
|
|
+ $found = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!$found) {
|
|
|
+ $data[] = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+
|
|
|
+ private function getMemberData()
|
|
|
+ {
|
|
|
+ $data = [];
|
|
|
+ for ($i = 6; $i >= 0; $i--) {
|
|
|
+ $found = false;
|
|
|
+ foreach ($this->members as $member) {
|
|
|
+ if (date("Y-m-d", strtotime($member->created_at)) == date("Y-m-d", strtotime('-' . $i . ' days'))) {
|
|
|
+ $data[] = $member->total;
|
|
|
+ $found = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!$found) {
|
|
|
+ $data[] = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
}
|