*/ public function share(Request $request): array { return array_merge(parent::share($request), [ 'auth' => [ 'user' => function () use ($request) { $user = $request->user(); if (! $user) { return null; } return [ 'id' => $user->id, 'name' => $user->name, 'email' => $user->email, 'roles' => $user->roles()->select('id', 'name', 'slug')->get(), 'permissions' => $user->permissions()->pluck('slug')->values(), ]; }, ], 'flash' => [ 'success' => fn () => $request->session()->get('success'), 'error' => fn () => $request->session()->get('error'), 'warning' => fn () => $request->session()->get('warning'), 'info' => fn () => $request->session()->get('info'), ], 'notifications' => function () use ($request) { try { $user = $request->user(); if (! $user) { return null; } $today = now()->toDateString(); // Base fetch to avoid serialization issues; eager load relations afterwards $activities = \App\Models\Activity::query() ->select(['id', 'due_date', 'amount', 'contract_id', 'client_case_id', 'created_at']) ->whereDate('due_date', $today) // Exclude activities that have been marked as read by this user ->whereNotExists(function ($q) use ($user, $today) { $q->select(\DB::raw(1)) ->from('activity_notification_reads') ->whereColumn('activity_notification_reads.activity_id', 'activities.id') ->where('activity_notification_reads.user_id', $user->id) ->whereDate('activity_notification_reads.due_date', '<=', $today) ->whereNotNull('activity_notification_reads.read_at'); }) ->orderBy('created_at') ->limit(20) ->get(); // Eager load needed relations (contracts and client cases) with qualified selects $activities->load([ 'contract' => function ($q) { $q->select(['contracts.id', 'contracts.uuid', 'contracts.reference', 'contracts.client_case_id']) ->with([ // Include client (via case) so the UI can render client.person.full_name 'clientCase' => function ($qq) { // Include person_id to ensure nested person loads correctly and to avoid null clientCase due to narrow selects $qq->select(['client_cases.id', 'client_cases.uuid', 'client_cases.client_id', 'client_cases.person_id']) ->with([ 'client' => function ($qqq) { $qqq->select(['clients.id', 'clients.person_id']) ->with([ 'person' => function ($qqqq) { $qqqq->select(['person.id', 'person.full_name']); }, ]); }, ]); }, 'account' => function ($qq) { $qq->select(['accounts.id', 'accounts.contract_id', 'accounts.balance_amount', 'accounts.initial_amount']); }, ]); }, 'clientCase' => function ($q) { $q->select(['client_cases.id', 'client_cases.uuid', 'client_cases.person_id', 'client_cases.client_id']) ->with([ 'person' => function ($qq) { $qq->select(['person.id', 'person.full_name']); }, 'client' => function ($qq) { $qq->select(['clients.id', 'clients.person_id']) ->with([ 'person' => function ($qqq) { $qqq->select(['person.id', 'person.full_name']); }, ]); }, ]); }, ]); // For convenience on the frontend, mirror client onto the contract so it can be accessed as contract.client.person // 1) Build a map of contract_id -> client_id using a lightweight join $contractIds = $activities->pluck('contract_id')->filter()->unique()->values(); if ($contractIds->isNotEmpty()) { $mapContractToClient = \App\Models\Contract::query() ->whereIn('contracts.id', $contractIds) ->join('client_cases', 'client_cases.id', '=', 'contracts.client_case_id') ->pluck('client_cases.client_id', 'contracts.id'); // 2) Load all needed clients with their person $clientIds = $mapContractToClient->filter()->unique()->values(); $clientsById = $clientIds->isNotEmpty() ? \App\Models\Client::query() ->whereIn('clients.id', $clientIds) ->with(['person:id,full_name']) ->get(['clients.id', 'clients.uuid', 'clients.person_id']) ->keyBy('id') : collect(); // 3) Attach client relation on each contract instance foreach ($activities as $act) { $contract = $act->getRelation('contract'); if (! $contract) { continue; } $cid = $mapContractToClient->get($contract->id); if ($cid && $clientsById->has($cid)) { $contract->setRelation('client', $clientsById->get($cid)); } } } return [ 'dueToday' => [ 'count' => $activities->count(), 'items' => $activities, 'date' => $today, ], ]; } catch (\Throwable $e) { return null; } }, ]); } }