feat: add RandomMovie component for enhanced user experience; implement movie filtering and random selection functionality, and update page layout to include new component
This commit is contained in:
parent
af4689d726
commit
68fb45d6ef
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 80,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"arrowParens": "avoid"
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
import { GenreList } from "@/components/molecules/GenreList";
|
import { GenreList } from '@/components/molecules/GenreList';
|
||||||
import { MovieList } from "@/components/molecules/MovieList";
|
import { MovieList } from '@/components/molecules/MovieList';
|
||||||
import { TrackedMovies } from "@/components/molecules/TrackedMovies";
|
import { RandomMovie } from '@/components/molecules/RandomMovie';
|
||||||
|
import { TrackedMovies } from '@/components/molecules/TrackedMovies';
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TrackedMovies />
|
<TrackedMovies />
|
||||||
<MovieList heading="Moja lista" />
|
<MovieList heading="Moja lista" />
|
||||||
|
<RandomMovie heading="Ciężko wybrać?" />
|
||||||
<GenreList heading="Odkrywaj nowe filmy według gatunku" />
|
<GenreList heading="Odkrywaj nowe filmy według gatunku" />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
'use client';
|
||||||
|
import { FC, useMemo, useState } from 'react';
|
||||||
|
import { useGlobalStore } from '@/app/store/globalStore';
|
||||||
|
import { Button } from '@/components/atoms/Button';
|
||||||
|
import { FaDice } from 'react-icons/fa';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { Movie } from '@/types/global';
|
||||||
|
|
||||||
|
type StoreFilter = 'all' | 'not_seen' | 'released' | 'favorites' | 'to_watch';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
heading?: string;
|
||||||
|
storeFilter?: StoreFilter;
|
||||||
|
colors?: keyof typeof colorsMap;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RandomMovie: FC<Props> = ({
|
||||||
|
heading = 'Losowy film',
|
||||||
|
storeFilter = 'not_seen',
|
||||||
|
colors = 'purple',
|
||||||
|
className = '',
|
||||||
|
}) => {
|
||||||
|
const { movies } = useGlobalStore();
|
||||||
|
const [selectedMovie, setSelectedMovie] = useState<Movie | null>(null);
|
||||||
|
|
||||||
|
// Filter movies based on the selected store filter.
|
||||||
|
const filteredMovies = useMemo(() => {
|
||||||
|
const today = new Date();
|
||||||
|
|
||||||
|
return movies.filter(movie => {
|
||||||
|
switch (storeFilter) {
|
||||||
|
case 'not_seen':
|
||||||
|
return !movie.seen;
|
||||||
|
case 'released':
|
||||||
|
return new Date(movie.release_date) < today;
|
||||||
|
case 'favorites':
|
||||||
|
return movie.favorite;
|
||||||
|
case 'to_watch':
|
||||||
|
return !movie.seen && new Date(movie.release_date) < today;
|
||||||
|
case 'all':
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [movies, storeFilter]);
|
||||||
|
|
||||||
|
const handleRandomize = () => {
|
||||||
|
if (filteredMovies.length === 0) return;
|
||||||
|
|
||||||
|
const randomIndex = Math.floor(Math.random() * filteredMovies.length);
|
||||||
|
const randomMovie = filteredMovies[randomIndex];
|
||||||
|
|
||||||
|
setSelectedMovie(randomMovie);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (filteredMovies.length === 0) {
|
||||||
|
return (
|
||||||
|
<section className={`blocks ${className}`}>
|
||||||
|
<div className="container">
|
||||||
|
{heading && (
|
||||||
|
<div className="flex items-center gap-3 mb-6">
|
||||||
|
<div className={`p-2 rounded-lg ${colorsMap[colors]}`}>
|
||||||
|
<FaDice className="text-white" />
|
||||||
|
</div>
|
||||||
|
<h2
|
||||||
|
className={`text-3xl font-bold ${colorsMap[colors]} bg-clip-text text-transparent`}
|
||||||
|
>
|
||||||
|
{heading}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="text-center py-12">
|
||||||
|
<p className="text-text/60 text-lg">Brak filmów w kategorii</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={`blocks ${className}`}>
|
||||||
|
<div className="container">
|
||||||
|
{heading && (
|
||||||
|
<div className="flex justify-center mb-6">
|
||||||
|
<h2
|
||||||
|
className={`text-3xl font-bold ${colorsMap[colors]} bg-clip-text text-transparent`}
|
||||||
|
>
|
||||||
|
{heading}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="text-center mb-4">
|
||||||
|
<p className="text-text/70 text-sm">
|
||||||
|
Dostępnych {filteredMovies.length} filmów
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
theme="secondary"
|
||||||
|
onClick={handleRandomize}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<FaDice />
|
||||||
|
Losuj film
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{selectedMovie && (
|
||||||
|
<div className="text-center mt-4">
|
||||||
|
<h3 className="text-2xl font-bold">
|
||||||
|
<Link href={`/film/${selectedMovie.id}`}>
|
||||||
|
{selectedMovie.title}
|
||||||
|
</Link>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const colorsMap = {
|
||||||
|
white: 'bg-gradient-to-r from-white to-gray-300',
|
||||||
|
yellow: 'bg-gradient-to-r from-yellow-400 to-orange-400',
|
||||||
|
blue: 'bg-gradient-to-r from-blue-400 to-purple-400',
|
||||||
|
green: 'bg-gradient-to-r from-green-400 to-teal-400',
|
||||||
|
red: 'bg-gradient-to-r from-red-400 to-pink-400',
|
||||||
|
purple: 'bg-gradient-to-r from-purple-400 to-pink-400',
|
||||||
|
orange: 'bg-gradient-to-r from-orange-400 to-yellow-400',
|
||||||
|
pink: 'bg-gradient-to-r from-pink-400 to-purple-400',
|
||||||
|
teal: 'bg-gradient-to-r from-teal-400 to-green-400',
|
||||||
|
gray: 'bg-gradient-to-r from-gray-400 to-gray-400',
|
||||||
|
};
|
||||||
73
todo.md
73
todo.md
|
|
@ -1,36 +1,51 @@
|
||||||
#
|
UI/UX Improvements
|
||||||
|
Dark/Light Mode Toggle - Obecnie tylko ciemny motyw
|
||||||
|
Responsywny design na urządzenia mobilne - Niektóre komponenty mogą wymagać poprawy
|
||||||
|
Loading states - Dodać skeletony zamiast spinnerów
|
||||||
|
Infinite scroll - Zamiast paginacji dla lepszego UX
|
||||||
|
Gesture support - Swipe na mobilnych dla akcji (dodaj/usuń film)
|
||||||
|
|
||||||
## ✅ `TODO.md` – Etapy rozwoju aplikacji
|
Zarządzanie filmami
|
||||||
|
Własne notatki do filmów - Pole w bazie danych już wspomniane w README
|
||||||
|
Tagi/kategorie użytkownika - Własne etykiety
|
||||||
|
Oceny użytkownika - Osobne od TMDB
|
||||||
|
Data obejrzenia - Kiedy użytkownik obejrzał film
|
||||||
|
Lista "Do obejrzenia" - Oddzielna od "Obejrzane"
|
||||||
|
Planowanie seansów - Kalendarz z datami
|
||||||
|
Eksport/import listy - JSON/CSV backup
|
||||||
|
|
||||||
```md
|
Funkcje społecznościowe
|
||||||
# TODO – MovieBox
|
Udostępnianie list - Link do publicznej listy
|
||||||
|
Rekomendacje na podstawie gustu - ML/AI sugestie
|
||||||
|
Porównanie list z znajomymi - Wspólne filmy
|
||||||
|
|
||||||
## 🔧 Faza 1 – MVP (funkcjonalna wersja lokalna)
|
Dodatkowe dane i integracje
|
||||||
|
Informacje o aktorach - Rozszerzone profile (już częściowo jest)
|
||||||
|
Gdzie obejrzeć - Streaming platforms API
|
||||||
|
Zwiastuny - YouTube API integration
|
||||||
|
Recenzje użytkowników - Własne mini-forum
|
||||||
|
Galeria zdjęć z filmu - Więcej materiałów wizualnych
|
||||||
|
|
||||||
- [ ] Integracja z TMDB API (wyszukiwanie filmów)
|
Performance i techniczne
|
||||||
- [ ] Utworzenie bazy danych (SQLite + Drizzle)
|
PWA - Offline support, push notifications o premierach
|
||||||
- [ ] Modele: Movie, WatchlistEntry
|
Lepsze caching - Redis/SWR optimizations
|
||||||
- [ ] Dodanie filmu do watchlisty (z podglądem szczegółów)
|
Lazy loading - Obrazy i komponenty
|
||||||
- [ ] Lista “Do obejrzenia” i “Obejrzane”
|
Search indexing - Full-text search w bazie
|
||||||
- [ ] Możliwość dodania tagu lub notatki do filmu
|
API rate limiting - Lepsze zarządzanie requestami do TMDB
|
||||||
- [ ] UI (Tailwind + ShadCN) – responsywna siatka filmów
|
|
||||||
|
|
||||||
## 🌐 Faza 2 – Rozszerzenie
|
Statystyki i analytics
|
||||||
|
Dashboard statystyk - Filmy obejrzane/miesiąc, ulubione gatunki
|
||||||
|
Streak tracking - Dni z rzędu oglądania filmów
|
||||||
|
Cele filmowe - X filmów do obejrzenia w roku
|
||||||
|
Porównanie z poprzednimi latami - Trendy
|
||||||
|
|
||||||
- [ ] Podgląd dat premier z TMDB
|
Powiadomienia
|
||||||
- [ ] Filtrowanie według daty premiery
|
Email notifications - O premierach z listy
|
||||||
- [ ] Sortowanie / filtrowanie po tagach/statusie
|
Push notifications - PWA alerts
|
||||||
|
Reminder system - Przypomnienia o filmach do obejrzenia
|
||||||
|
|
||||||
## 🔐 Faza 3 – Rozszerzenia prywatne
|
Baza danych i backend
|
||||||
|
Migracja na PostgreSQL - Jak wspomniano w README
|
||||||
- [ ] Dodanie Auth.js (logowanie)
|
User authentication - Currently brak systemu użytkowników
|
||||||
- [ ] Migracja bazy do PostgreSQL
|
API endpoints - Własne REST API
|
||||||
- [ ] Eksport listy filmów (np. JSON)
|
Backup system - Automatyczne kopie zapasowe
|
||||||
- [ ] Backup na GitHub (np. GitHub Actions)
|
|
||||||
|
|
||||||
## 💡 Pomysły na później
|
|
||||||
|
|
||||||
- [ ] System rekomendacji (podobne filmy)
|
|
||||||
- [ ] Powiadomienia o premierach
|
|
||||||
- [ ] Integracja z Letterboxd
|
|
||||||
```
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue