diff --git a/app/Livewire/Forms/FilterForm.php b/app/Livewire/Forms/FilterForm.php new file mode 100644 index 0000000..5a1ab3d --- /dev/null +++ b/app/Livewire/Forms/FilterForm.php @@ -0,0 +1,11 @@ +name = $list->name; + $this->listId = $list->id; + $this->isPublic = $list->is_public; + } + + public function save(): void + { + if ($this->listId) { + $list = MovieList::find($this->listId); + $list->name = $this->name; + $list->is_public = $this->isPublic; + $list->save(); + } + } +} diff --git a/app/Livewire/MovieDetailsPanel.php b/app/Livewire/MovieDetailsPanel.php new file mode 100644 index 0000000..49789bc --- /dev/null +++ b/app/Livewire/MovieDetailsPanel.php @@ -0,0 +1,31 @@ + 'openPanel']; + + public function openPanel(int $movieId): void + { + $this->selectedMovie = Movie::find($movieId); + $this->showDetails = true; + } + + public function closePanel(): void + { + $this->showDetails = false; + $this->selectedMovie = null; + } + + public function render() + { + return view('livewire.movie-details-panel'); + } +} diff --git a/app/Livewire/MovieList.php b/app/Livewire/MovieList.php index b9a678b..a2c6730 100644 --- a/app/Livewire/MovieList.php +++ b/app/Livewire/MovieList.php @@ -3,18 +3,25 @@ namespace App\Livewire; use App\Livewire\Forms\MovieListForm; -use App\Models\Interfaces\MovieDbInterface; +use App\Livewire\Forms\SettingsForm; use App\Models\MovieList as MovieListModel; use Livewire\Component; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class MovieList extends Component { public int $id; - public string $query; public MovieListModel $list; public $movies = []; + public string $filterText = ""; + public $filteredMovies = []; public MovieListForm $form; + public SettingsForm $settingsForm; + public bool $showSettings = false; + + protected $listeners = [ + 'movie-added' => 'getList', + 'list-updated' => 'getList' + ]; public function mount($id): void { @@ -30,25 +37,33 @@ class MovieList extends Component if ($list) { $this->list = $list; $this->movies = $list->movies; + $this->filteredMovies = $list->movies; + $this->settingsForm->setList($list); } else { abort(404); } } - public function addMovie(MovieDbInterface $movie_db) + public function filterMovies(): void { - $this->resetErrorBag(); + $this->filteredMovies = collect($this->movies) + ->filter(fn($movie) => stripos($movie->title, $this->filterText) !== false); + } - try { - $movie = $movie_db->search($this->query); - } catch (NotFoundHttpException $e) { - $this->addError('query', 'Movie not found'); - return; - } + public function toggleSettings(): void + { + $this->showSettings = !$this->showSettings; + } - $this->list->movies()->syncWithoutDetaching($movie->id); + public function saveSettings(): void + { + $this->settingsForm->save(); $this->getList(); - $this->form->reset(); + } + + public function updatedSettingsForm(): void + { + $this->settingsForm->save(); } public function render() diff --git a/app/Livewire/SearchPanel.php b/app/Livewire/SearchPanel.php new file mode 100644 index 0000000..cd42b8e --- /dev/null +++ b/app/Livewire/SearchPanel.php @@ -0,0 +1,54 @@ + 'openSearchPanel']; + + public function openSearchPanel(): void + { + $this->showSearch = true; + } + + public function findMovies(MovieDbInterface $movie_db): void + { + try { + //$movie = $movie_db->search($this->query, ["type" => "imdb"]); + $this->results = $movie_db->search($this->query, ["type" => "title"]); + } catch (NotFoundHttpException $e) { + $this->addError('query', 'Movie not found'); + } + } + + public function addMovie(MovieDbInterface $movieDb, string $imdbId): void + { + $this->resetErrorBag(); + $movie = $movieDb->searchByImdbId($imdbId); + + $list = MovieListModel::find($this->listId); + $list->movies()->syncWithoutDetaching($movie->id); + + $this->dispatch('movie-added'); + $this->showSearch = false; + $this->query = ''; + $this->results = []; + } + + public function render() + { + return view('livewire.search-panel'); + } +} diff --git a/app/Providers/FortifyServiceProvider.php b/app/Providers/FortifyServiceProvider.php index d42ec0c..0dc5d38 100644 --- a/app/Providers/FortifyServiceProvider.php +++ b/app/Providers/FortifyServiceProvider.php @@ -10,6 +10,7 @@ use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Str; use Laravel\Fortify\Fortify; +use Laravel\Fortify\Contracts\LoginResponse; class FortifyServiceProvider extends ServiceProvider { diff --git a/app/Services/OmdbService.php b/app/Services/OmdbService.php index 96b95f7..9dcc871 100644 --- a/app/Services/OmdbService.php +++ b/app/Services/OmdbService.php @@ -8,6 +8,7 @@ use App\Models\User; use Exception; use Illuminate\Support\Facades\Http; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use function Symfony\Component\Translation\t; class OmdbService implements MovieDbInterface { @@ -20,14 +21,26 @@ class OmdbService implements MovieDbInterface $this->user = auth()->user(); } - public function search(string $query, array $options = []) + public function search(string $query, array $options = []): array|Movie { - $movie = Http::get($this->url . "&t=" . $query)->json(); + $searchType = $options["type"] ?? "title"; + + $result = match ($searchType) { + 'imdb' => $this->searchByImdbId($query), + 'title' => $this->searchByTitle($query), + default => $this->searchByTitle($query), + }; + + return $result; + } + + public function searchByImdbId(string $imdbId) + { + $movie = Http::get($this->url . "&i=" . $imdbId)->json(); if ($movie['Response'] !== 'True') { throw new NotFoundHttpException("Movie not found"); } - logger()->debug("Movie from OMDB: " . json_encode($movie)); try { $existing_movie = $this->movie->where('imdb_id', $movie['imdbID'])->firstOrFail(); return $existing_movie; @@ -38,4 +51,25 @@ class OmdbService implements MovieDbInterface ); } } + + public function searchByTitle(string $title) + { + $search_results = Http::get($this->url . "&s=" . $title . "&type=movie")->json(); + if ($search_results['Response'] !== 'True') { + throw new NotFoundHttpException("Movie not found"); + } + + $movies = []; + foreach ($search_results['Search'] as $result) { + $movies[] = [ + 'title' => $result['Title'] ?? "", + 'year' => $result['Year'] ?? "", + 'imdb_id' => $result['imdbID'] ?? "", + 'type' => $result['Type'] ?? "", + 'poster' => $result['Poster'] ?? "" + ]; + } + + return $movies; + } } diff --git a/config/fortify.php b/config/fortify.php index 2fce0cc..a0d6f4f 100644 --- a/config/fortify.php +++ b/config/fortify.php @@ -73,7 +73,7 @@ return [ | */ - 'home' => '/dashboard', + 'home' => '/lists', /* |-------------------------------------------------------------------------- diff --git a/package-lock.json b/package-lock.json index 47584d1..197486d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "packages": { "": { "dependencies": { + "@fortawesome/fontawesome-free": "^7.1.0", "@tailwindcss/vite": "^4.1.11", "autoprefixer": "^10.4.20", "axios": "^1.7.4", @@ -448,6 +449,15 @@ "node": ">=18" } }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.1.0.tgz", + "integrity": "sha512-+WxNld5ZCJHvPQCr/GnzCTVREyStrAJjisUPtUxG5ngDA8TMlPnKp6dddlTpai4+1GNmltAeuk1hJEkBohwZYA==", + "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)", + "engines": { + "node": ">=6" + } + }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", diff --git a/package.json b/package.json index 6a891b6..31cc403 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "dev": "vite" }, "dependencies": { + "@fortawesome/fontawesome-free": "^7.1.0", "@tailwindcss/vite": "^4.1.11", "autoprefixer": "^10.4.20", "axios": "^1.7.4", diff --git a/resources/css/app.css b/resources/css/app.css index 2f9e968..29a1edc 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,4 +1,5 @@ @import 'tailwindcss'; +@import '@fortawesome/fontawesome-free/css/all.css'; @source '../views'; @source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; diff --git a/resources/views/components/header.blade.php b/resources/views/components/header.blade.php index 6fee84d..6627bae 100644 --- a/resources/views/components/header.blade.php +++ b/resources/views/components/header.blade.php @@ -1,9 +1,9 @@ -