*/ public array $expandedFeeds = []; public function setTab(string $tab): void { $this->tab = $tab; $this->search = ''; $this->expandedFeeds = []; $this->resetPage(); } public function updatedFeedId(): void { $this->expandedFeeds = []; $this->resetPage(); } public function toggleFeed(int $feedId): void { if (isset($this->expandedFeeds[$feedId])) { unset($this->expandedFeeds[$feedId]); return; } $this->expandedFeeds[$feedId] = true; } public function updatedSearch(): void { $this->resetPage(); } public function approve(int $routeArticleId): void { RouteArticle::findOrFail($routeArticleId)->approve(); } public function reject(int $routeArticleId): void { RouteArticle::findOrFail($routeArticleId)->reject(); } public function restore(int $routeArticleId): void { $routeArticle = RouteArticle::findOrFail($routeArticleId); $routeArticle->update([ 'approval_status' => ApprovalStatusEnum::PENDING, 'decided_at' => null, ]); } public function clear(): void { $feed = $this->feedId !== null ? Feed::find($this->feedId) : null; $cleared = $this->clearableQuery()->update([ 'approval_status' => ApprovalStatusEnum::REJECTED, 'decided_at' => now(), ]); if ($cleared > 0) { ActivityLogged::dispatch( ActivityTypeEnum::REJECT, $feed !== null ? "Cleared {$cleared} pending articles from {$feed->name}" : "Cleared {$cleared} pending articles", ['cleared' => $cleared], $feed, ); } $this->expandedFeeds = []; } /** * @return Builder */ private function clearableQuery(): Builder { return RouteArticle::query() ->where('approval_status', ApprovalStatusEnum::PENDING) ->when($this->feedId !== null, fn (Builder $q) => $q->where('feed_id', $this->feedId)); } public function refresh(): void { $this->isRefreshing = true; ArticleDiscoveryJob::dispatch(); $this->dispatch('refresh-started'); } public function retryPublish(int $routeArticleId): void { $routeArticle = RouteArticle::failed()->find($routeArticleId); if (! $routeArticle instanceof RouteArticle) { return; } $routeArticle->clearPublishFailure(); ActivityLogged::dispatch( ActivityTypeEnum::PUBLISH, "Queued \"{$routeArticle->article->title}\" for another publish attempt", ['route_article_id' => $routeArticle->id], $routeArticle->article, ); } public function render(): View { $pendingCount = RouteArticle::where('approval_status', ApprovalStatusEnum::PENDING)->count(); $failedCount = RouteArticle::failed()->count(); if ($this->tab === 'pending') { return view('livewire.articles', [ 'routeArticles' => null, 'pendingFeeds' => $this->pendingFeeds(), 'feedOptions' => $this->feedOptions(), 'pendingCount' => $pendingCount, 'failedCount' => $failedCount, 'clearableCount' => $this->clearableQuery()->count(), ])->layout('layouts.app'); } $query = RouteArticle::with(['article.feed', 'feed', 'platformChannel']) ->orderBy('created_at', 'desc'); if ($this->tab === 'failed') { $query->failed(); } if ($this->feedId !== null) { $query->where('feed_id', $this->feedId); } if ($this->search !== '') { $search = $this->search; $query->whereHas('article', function ($q) use ($search) { $q->where('title', 'like', "%{$search}%") ->orWhere('description', 'like', "%{$search}%"); }); } return view('livewire.articles', [ 'routeArticles' => $query->paginate(15), 'pendingFeeds' => null, 'feedOptions' => $this->feedOptions(), 'pendingCount' => $pendingCount, 'failedCount' => $failedCount, 'clearableCount' => 0, ])->layout('layouts.app'); } /** * @return Collection */ private function pendingFeeds(): Collection { $counts = RouteArticle::query() ->selectRaw('feed_id, COUNT(*) as aggregate') ->where('approval_status', ApprovalStatusEnum::PENDING) ->when($this->feedId !== null, fn ($q) => $q->where('feed_id', $this->feedId)) ->groupBy('feed_id') ->pluck('aggregate', 'feed_id'); return Feed::whereIn('id', $counts->keys())->get() ->map(fn (Feed $feed): PendingFeedGroup => new PendingFeedGroup( $feed, (int) $counts->get($feed->id, 0), isset($this->expandedFeeds[$feed->id]) ? $this->routeArticlesForFeed($feed->id) : null, )) ->sortByDesc('count') ->values(); } /** * @return EloquentCollection */ private function feedOptions(): EloquentCollection { return Feed::whereIn('id', RouteArticle::query()->select('feed_id')->distinct()) ->orderBy('name') ->get(); } /** * @return EloquentCollection */ private function routeArticlesForFeed(int $feedId): EloquentCollection { return RouteArticle::with(['article.feed', 'feed', 'platformChannel']) ->where('approval_status', ApprovalStatusEnum::PENDING) ->where('feed_id', $feedId) ->orderBy('created_at', 'desc') ->get(); } }