Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here

ash-jc-allen/find-a-pr

82 stars
3 code files
View ash-jc-allen/find-a-pr on GitHub

composer.json

Open in GitHub
{
//
"require": {
"php": "^8.1",
//
"livewire/livewire": "^2.10"
},
//
}

app/Http/Livewire/ListIssues.php

Open in GitHub
use App\DataTransferObjects\Issue;
use App\Services\IssueService;
use App\Services\RepoService;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cookie;
use Livewire\Component;
 
class ListIssues extends Component
{
private const SORTS = [
'random' => [
'friendly' => 'Random', 'field' => 'random',
],
'created_at' => [
'friendly' => 'Created At (Oldest First)', 'field' => 'createdAt', 'direction' => 'asc',
],
'created_at_desc' => [
'friendly' => 'Created At (Newest First)', 'field' => 'createdAt', 'direction' => 'desc',
],
'title' => [
'friendly' => 'Title (A-Z)', 'field' => 'title', 'direction' => 'asc',
],
'title_desc' => [
'friendly' => 'Title (Z-A)', 'field' => 'title', 'direction' => 'desc',
],
'repo_name' => [
'friendly' => 'Repo Name (A-Z)', 'field' => 'repoName', 'direction' => 'asc',
],
'repo_name_desc' => [
'friendly' => 'Repo Name (Z-A)', 'field' => 'repoName', 'direction' => 'desc',
],
];
 
public array $labels;
 
public Collection $repos;
 
public Collection $originalIssues;
 
public ?string $sortField = null;
 
public string $sortDirection = 'asc';
 
public ?string $sort = null;
 
public ?string $searchTerm = null;
 
public bool $shouldDisplayFirstTimeNotice;
 
public function mount(): void
{
$this->labels = config('repos.labels');
$this->repos = app(RepoService::class)->reposToCrawl()->sort();
 
$this->originalIssues = app(IssueService::class)->getAll()->shuffle();
 
$this->shouldDisplayFirstTimeNotice = ! Cookie::get('firstTimeNoticeClosed');
}
 
public function render(): View
{
$issues = $this->originalIssues
->when($this->searchTerm, $this->applySearch())
->when($this->sort, $this->applySort());
 
return view('livewire.list-issues', [
'issues' => $issues,
'sorts' => self::SORTS,
]);
}
 
public function hydrate(): void
{
$this->originalIssues = $this->originalIssues->map(
fn ($issueArray): Issue => Issue::fromArray($issueArray)
);
}
 
public function updatedSort(string $newSort): void
{
if (array_key_exists($newSort, self::SORTS)) {
$this->sortField = self::SORTS[$newSort]['field'];
$this->sortDirection = self::SORTS[$newSort]['direction'] ?? 'asc';
}
}
 
private function applySearch(): \Closure
{
return static function (Collection $issues, string $searchTerm): Collection {
$searchTerm = strtolower($searchTerm);
 
return $issues->filter(function (Issue $issue) use ($searchTerm): bool {
return str_contains(strtolower($issue->repoName), $searchTerm)
|| str_contains(strtolower($issue->title), $searchTerm);
});
};
}
 
private function applySort(): \Closure
{
return function (Collection $issues): Collection {
return $issues->sortBy($this->sortField, descending: $this->sortDirection === 'desc');
};
}
 
public function hideFirstTimeNotice(): void
{
$this->shouldDisplayFirstTimeNotice = false;
 
Cookie::queue('firstTimeNoticeClosed', true, 40_320);
}
}

resources/views/livewire/list-issues.blade.php

Open in GitHub
<div class="mt-12 flex">
<x-side-bar :repos="$repos" :labels="$labels" :sorts="$sorts"/>
 
<main class="w-full md:w-3/4">
<div class="flex justify-end items-center flex-wrap space-y-2 md:space-y-0">
<p class="text-right">
Found <span class="font-bold">{{ count($issues) }}</span> issue(s)
</p>
</div>
 
@if($shouldDisplayFirstTimeNotice)
<x-first-time-notice/>
@endif
 
@forelse($issues as $issue)
<x-issue-card :issue="$issue"/>
@empty
<div class="my-14 text-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-24 w-24 text-gray-300 mx-auto" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
 
<p class="font-medium my-4">No Issues Found!</p>
<p>It looks there aren't any issues that fit your criteria.</p>
</div>
@endforelse
</main>
</div>

We'd Love Your Feedback

Tell us what you like or what we can improve

Feel free to share anything you like or dislike about this page or the platform in general.