user(); if (! $user) { abort(403); } $today = now()->toDateString(); $perPage = max(1, min(100, (int) $request->integer('perPage', 15))); $search = trim((string) $request->input('search', '')); $clientUuid = trim((string) $request->input('client', '')); $clientId = null; $clientCaseIdsForFilter = collect(); if ($clientUuid !== '') { $clientId = Client::query()->where('uuid', $clientUuid)->value('id'); if ($clientId) { $clientCaseIdsForFilter = ClientCase::query()->where('client_id', $clientId)->pluck('id'); } } $query = Activity::query() ->select(['id', 'due_date', 'amount', 'contract_id', 'client_case_id', 'created_at']) ->whereNotNull('due_date') ->whereDate('due_date', '<=', $today) // Removed per-user unread filter: show notifications regardless of individual reads ->when($clientCaseIdsForFilter->isNotEmpty(), function ($q) use ($clientCaseIdsForFilter) { // Filter by clients: activities directly on any of the client's cases OR via contracts under those cases $q->where(function ($qq) use ($clientCaseIdsForFilter) { $qq->whereIn('activities.client_case_id', $clientCaseIdsForFilter) ->orWhereIn('activities.contract_id', Contract::query() ->select('id') ->whereIn('client_case_id', $clientCaseIdsForFilter) ); }); }) // allow simple search by contract reference or person name ->when($search !== '', function ($q) use ($search) { $s = mb_strtolower($search); $q->leftJoin('contracts', 'contracts.id', '=', 'activities.contract_id') ->leftJoin('client_cases', 'client_cases.id', '=', 'activities.client_case_id') ->leftJoin('person', 'person.id', '=', 'client_cases.person_id') ->where(function ($qq) use ($s) { $qq->whereRaw('LOWER(COALESCE(contracts.reference, \'\')) LIKE ?', ['%'.$s.'%']) ->orWhereRaw('LOWER(COALESCE(person.full_name, \'\')) LIKE ?', ['%'.$s.'%']); }); }) ->with([ 'contract' => function ($q) { $q->select(['contracts.id', 'contracts.uuid', 'contracts.reference', 'contracts.client_case_id']) ->with([ 'clientCase' => function ($qq) { $qq->select(['client_cases.id', 'client_cases.uuid', 'client_cases.client_id']) ->with([ 'client' => function ($qqq) { $qqq->select(['clients.id', 'clients.uuid', '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.uuid', 'clients.person_id']) ->with([ 'person' => function ($qqq) { $qqq->select(['person.id', 'person.full_name']); }, ]); }, ]); }, ]) // force ordering by due_date DESC only ->orderByDesc('activities.due_date'); // Use a custom page parameter name to match the frontend DataTableServer $activities = $query->paginate($perPage, ['*'], 'unread-page')->withQueryString(); // Build a distinct clients list for the filter (client UUID + client.person.full_name) // Collect client_case_ids from both direct activities and via contracts $baseForClients = Activity::query() ->select(['contract_id', 'client_case_id']) ->whereNotNull('due_date') ->whereDate('due_date', '<=', $today) // Removed per-user unread filter for client list base ->when($clientCaseIdsForFilter->isNotEmpty(), function ($q) use ($clientCaseIdsForFilter) { $q->where(function ($qq) use ($clientCaseIdsForFilter) { $qq->whereIn('activities.client_case_id', $clientCaseIdsForFilter) ->orWhereIn('activities.contract_id', Contract::query()->select('id')->whereIn('client_case_id', $clientCaseIdsForFilter)); }); }) ->get(); $contractIds = $baseForClients->pluck('contract_id')->filter()->unique()->values(); $directCaseIds = $baseForClients->pluck('client_case_id')->filter()->unique()->values(); $mapContractToCase = $contractIds->isNotEmpty() ? Contract::query()->whereIn('id', $contractIds)->pluck('client_case_id', 'id') : collect(); $caseIds = $directCaseIds ->merge($contractIds->map(fn ($cid) => $mapContractToCase->get($cid))) ->filter() ->unique() ->values(); // Map caseIds -> clientIds, then load clients and present as value(label) $clientIds = $caseIds->isNotEmpty() ? ClientCase::query()->whereIn('id', $caseIds)->pluck('client_id')->filter()->unique()->values() : collect(); $clients = $clientIds->isNotEmpty() ? Client::query() ->whereIn('id', $clientIds) ->with(['person:id,full_name']) ->get(['id', 'uuid', 'person_id']) ->map(fn ($c) => [ 'value' => $c->uuid, 'label' => optional($c->person)->full_name ?: '(neznana stranka)', ]) ->sortBy('label', SORT_NATURAL | SORT_FLAG_CASE) ->values() : collect(); return Inertia::render('Notifications/Unread', [ 'activities' => $activities, 'today' => $today, 'clients' => $clients, ]); } }