Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 21 additions & 34 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,41 @@
// hooks
import { useState } from 'react';
import { usePopMovies, useCurMovies, useSearchMovies } from './hooks/useMovies';
import { usePopularPeople } from './hooks/usePeople';
import { Sidebar } from './components/Sidebar';
import { Section } from './components/Section';
import { MovieList } from './components/MovieList';
import { PersonList } from './components/PersonList';
import { useSearchMovies } from './hooks/useMovies';
import { useDebouncedValue } from './hooks/useDebouncedValue';

import { useSessionStorage } from './hooks/useSessionStorage';
/* Brukes denne til noe Leona? */
import { sortAndFilterMovies, type SortOption } from './utils/sortAndFilterMovies';

import { useSessionStorage } from './hooks/useSessionStorage';
import { SortFilterBar } from './components/SortFilterBar';
import { useFavorites } from './hooks/useFavorites';
import { TrendingPreview } from './components/TrendingPreview';
import { MovieDetails } from './components/MovieDetails';

// layout templates og components
import { SearchLayout } from './layout/SearchLayout';
import { MainLayout } from './layout/MainLayout';
import { Sidebar } from './components/Sidebar';

// Movie type, holder all informajson om en film
import type { Movie } from './types/tmdb';

import './App.css';

function App() {

const [query, setQuery] = useState('');
// brukes for å kunne velge film å vise detaljer om
const [selectedMovie, setSelectedMovie] = useState<Movie | null>(null);

// sorterings-funksjonalitet ?
const [sortBy, setSortBy] = useSessionStorage<SortOption>('sortBy', 'popularity');
const [minRating, setMinRating] = useSessionStorage<number>('minRating', 0);

const popular = usePopMovies()
const current = useCurMovies()
const people = usePopularPeople()
// search query var setter
const [query, setQuery] = useState('');
const debouncedQuery = useDebouncedValue(query, 400);
const search = useSearchMovies(debouncedQuery)
const isSearching = query.trim().length > 0;

// favorite-funksjonalitet
const { isFavorite, toggleFavorite} = useFavorites();

return (
Expand All @@ -46,33 +50,16 @@ function App() {
onMinRatingChange={setMinRating}
/>
{isSearching ? (
<Section id="sok" title={`Søkeresultater for "${query}"`} isLoading={search.isLoading} error={search.error}>
{search.data && <MovieList movies={search.data} isFavorite={isFavorite} onToggleFavorite={toggleFavorite} onSelectMovie={setSelectedMovie} />}
</Section>
) : (
<>
<Section id="trendingPreview" title="" isLoading={current.isLoading} error={current.error}>
{current.data && <TrendingPreview movies={current.data} onSelectMovie={setSelectedMovie}/>}
</Section>

<Section id="populaere" title="Populære filmer" isLoading={popular.isLoading} error={popular.error}>
{popular.data && <MovieList movies={popular.data} isFavorite={isFavorite} onToggleFavorite={toggleFavorite} onSelectMovie={setSelectedMovie} />}
</Section>

<Section id="nye-filmer" title="Nye filmer" isLoading={current.isLoading} error={current.error}>
{current.data && <MovieList movies={current.data} isFavorite={isFavorite} onToggleFavorite={toggleFavorite} onSelectMovie={setSelectedMovie} />}
</Section>

<Section id="skuespillere" title="Skuespillere" isLoading={people.isLoading} error={people.error}>
{people.data && <PersonList people={people.data.results} />}
</Section>
</>
<SearchLayout query={query} search={search} isFavorite={isFavorite} toggleFavorite={toggleFavorite} onSelectMovie={setSelectedMovie} />
) : (
<MainLayout isFavorite={isFavorite} toggleFavorite={toggleFavorite} onSelectMovie={setSelectedMovie} />
)}
</main>

{selectedMovie && (
<MovieDetails movie={selectedMovie} isFavorite={isFavorite(selectedMovie.id)} onToggleFavorite={toggleFavorite} onClose={() => setSelectedMovie(null)} />
)}

<div className="page-spacer" aria-hidden="true"></div>
</div>
);
Expand Down
2 changes: 2 additions & 0 deletions src/components/MovieCard.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
transition: transform 0.15s ease, box-shadow 0.15s ease;

cursor: pointer;
}

.movie-card:hover {
Expand Down
2 changes: 1 addition & 1 deletion src/components/MovieDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function MovieDetails({ movie, isFavorite, onToggleFavorite, onClose }:
<div className="details-overlay" onClick={onClose}>
<div className="details-card" onClick={(e) => e.stopPropagation()}>
<img
src={`https://image.tmdb.org/t/p/original${movie.backdrop_path}`}
src={`https://image.tmdb.org/t/p/w1280${movie.backdrop_path}`}
alt={movie.title}
className="details-backdrop"
/>
Expand Down
10 changes: 10 additions & 0 deletions src/components/Section.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.section-skeleton {
border-radius: 0.5rem;
background: linear-gradient(90deg, #1a1a1a 25%, #2a2a2a 50%, #1a1a1a 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
5 changes: 3 additions & 2 deletions src/components/Section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ type SectionProps = {
isLoading: boolean;
error: Error | null;
children: ReactNode;
skeletonHeight?: string;
};

export function Section({ id, title, isLoading, error, children }: SectionProps) {
export function Section({ id, title, isLoading, error, children, skeletonHeight="300px"}: SectionProps) {
return (
<section id={id}>
<h2>{title}</h2>
{isLoading && <p>Laster...</p>}
{isLoading && <div className="section-skeleton" style={{height: skeletonHeight}}/>}
{error && <p>Noe gikk galt: {error.message}</p>}
{!isLoading && !error && children}
</section>
Expand Down
2 changes: 1 addition & 1 deletion src/components/TrendingPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
import type { Movie } from "../types/tmdb";
import "./TrendingPreview.css"

const tmdbURL = `https://image.tmdb.org/t/p/original`;
const tmdbURL = `https://image.tmdb.org/t/p/w1280`;

type TrendingPreviewProps = {
movies : Movie[];
Expand Down
37 changes: 37 additions & 0 deletions src/layout/MainLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { MovieList } from "../components/MovieList";
import { PersonList } from "../components/PersonList";
import { Section } from "../components/Section";
import { TrendingPreview } from "../components/TrendingPreview";
import { useCurMovies, usePopMovies } from "../hooks/useMovies";
import { usePopularPeople } from "../hooks/usePeople";
import type { Movie } from "../types/tmdb";

type MainLayoutProps = {
isFavorite: (id: number) => boolean;
toggleFavorite: (id: number) => void;
onSelectMovie: (movie: Movie) => void;
}

// HomeSections.tsx
export function MainLayout({ isFavorite, toggleFavorite, onSelectMovie }: MainLayoutProps) {
const popular = usePopMovies();
const current = useCurMovies();
const people = usePopularPeople();

return (
<>
<Section id="trendingPreview" title="" isLoading={current.isLoading} error={current.error} skeletonHeight="30vh">
{current.data && <TrendingPreview movies={current.data} onSelectMovie={onSelectMovie} />}
</Section>
<Section id="populaere" title="Populære filmer" isLoading={popular.isLoading} error={popular.error}>
{popular.data && <MovieList movies={popular.data} isFavorite={isFavorite} onToggleFavorite={toggleFavorite} onSelectMovie={onSelectMovie} />}
</Section>
<Section id="nye-filmer" title="Nye filmer" isLoading={current.isLoading} error={current.error}>
{current.data && <MovieList movies={current.data} isFavorite={isFavorite} onToggleFavorite={toggleFavorite} onSelectMovie={onSelectMovie} />}
</Section>
<Section id="skuespillere" title="Skuespillere" isLoading={people.isLoading} error={people.error}>
{people.data && <PersonList people={people.data.results} />}
</Section>
</>
);
}
22 changes: 22 additions & 0 deletions src/layout/SearchLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { UseQueryResult } from "@tanstack/react-query";
import type { Movie } from "../types/tmdb";
import { Section } from "../components/Section";
import { MovieList } from "../components/MovieList";

type SearchSectionProps = {
query: string;
search: UseQueryResult<Movie[], Error>; // or whatever your hook returns
isFavorite: (id: number) => boolean;
toggleFavorite: (id: number) => void;
onSelectMovie: (movie: Movie) => void;
};

export function SearchLayout({ query, search, isFavorite, toggleFavorite, onSelectMovie }: SearchSectionProps) {
return (
<Section id="sok" title={`Søkeresultater for "${query}"`} isLoading={search.isLoading} error={search.error}>
{search.data && (
<MovieList movies={search.data} isFavorite={isFavorite} onToggleFavorite={toggleFavorite} onSelectMovie={onSelectMovie} />
)}
</Section>
);
}