Add movie gallery, similar movies, and recommended movies components: integrate MovieGallery, SimilarMovies, and RecommendedMovies into the film detail page for enhanced user engagement. Update AuroraLayout to improve button visibility and interaction.
This commit is contained in:
parent
61395ca1ec
commit
dc0d7693c1
|
|
@ -1,5 +1,8 @@
|
||||||
import { HeroMovie } from "@/components/molecules/HeroMovie";
|
import { HeroMovie } from "@/components/molecules/HeroMovie";
|
||||||
import { MovieCast } from "@/components/molecules/MovieCast";
|
import { MovieCast } from "@/components/molecules/MovieCast";
|
||||||
|
import { SimilarMovies } from "@/components/molecules/SimilarMovies";
|
||||||
|
import { RecommendedMovies } from "@/components/molecules/RecommendedMovies";
|
||||||
|
import { MovieGallery } from "@/components/molecules/MovieGallery";
|
||||||
import { TMDB } from "@/lib/tmdb";
|
import { TMDB } from "@/lib/tmdb";
|
||||||
|
|
||||||
// Main movie details component.
|
// Main movie details component.
|
||||||
|
|
@ -16,6 +19,12 @@ export default async function Page({
|
||||||
<div className="min-h-screen mt-16">
|
<div className="min-h-screen mt-16">
|
||||||
<HeroMovie movieDetails={movieDetails} />
|
<HeroMovie movieDetails={movieDetails} />
|
||||||
<MovieCast movieDetails={movieDetails} />
|
<MovieCast movieDetails={movieDetails} />
|
||||||
|
<MovieGallery
|
||||||
|
images={movieDetails.images}
|
||||||
|
movieTitle={movieDetails.title}
|
||||||
|
/>
|
||||||
|
<SimilarMovies movies={movieDetails.similar} />
|
||||||
|
<RecommendedMovies movies={movieDetails.recommendations} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -205,17 +205,6 @@ export const AuroraLayout: FC<AuroraLayoutProps> = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{/* Zobacz więcej button */}
|
|
||||||
<Link
|
|
||||||
href={`/film/${id}`}
|
|
||||||
className="opacity-0 group-hover:opacity-100 transition-all duration-300 transform group-hover:scale-105"
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-2 bg-gradient-to-r from-purple-600/90 to-pink-600/90 hover:from-purple-500 hover:to-pink-500 px-3 py-2 rounded-lg text-white text-sm font-medium shadow-lg border border-white/10 transition-all duration-300">
|
|
||||||
<FaInfoCircle size={14} />
|
|
||||||
<span>Zobacz więcej</span>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
{alreadyInStore && (
|
{alreadyInStore && (
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{seen && (
|
{seen && (
|
||||||
|
|
@ -234,6 +223,17 @@ export const AuroraLayout: FC<AuroraLayoutProps> = ({
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Zobacz więcej button */}
|
||||||
|
<Link
|
||||||
|
href={`/film/${id}`}
|
||||||
|
className="transform hover:scale-105 transition-all duration-300 mt-4 flex justify-center"
|
||||||
|
>
|
||||||
|
<div className="inline-flex items-center gap-2 bg-gradient-to-r from-purple-600/90 to-pink-600/90 hover:from-purple-500 hover:to-pink-500 px-3 py-2 rounded-lg text-white text-sm font-medium shadow-lg border border-white/10 transition-all duration-300">
|
||||||
|
<FaInfoCircle size={14} />
|
||||||
|
<span>Zobacz więcej</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Decorative border glow */}
|
{/* Decorative border glow */}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,214 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { FC, useState } from "react";
|
||||||
|
import {
|
||||||
|
FaImages,
|
||||||
|
FaTimes,
|
||||||
|
FaChevronLeft,
|
||||||
|
FaChevronRight,
|
||||||
|
} from "react-icons/fa";
|
||||||
|
|
||||||
|
type ImageData = {
|
||||||
|
aspect_ratio: number;
|
||||||
|
file_path: string;
|
||||||
|
height: number;
|
||||||
|
width: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
images: {
|
||||||
|
backdrops: ImageData[];
|
||||||
|
logos: ImageData[];
|
||||||
|
posters: ImageData[];
|
||||||
|
};
|
||||||
|
movieTitle: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MovieGallery: FC<Props> = ({ images, movieTitle }) => {
|
||||||
|
const [selectedCategory, setSelectedCategory] = useState<
|
||||||
|
"backdrops" | "posters" | "logos"
|
||||||
|
>("backdrops");
|
||||||
|
const [lightboxOpen, setLightboxOpen] = useState(false);
|
||||||
|
const [lightboxIndex, setLightboxIndex] = useState(0);
|
||||||
|
|
||||||
|
const allImages = {
|
||||||
|
backdrops: images.backdrops.slice(0, 12), // Limit to first 12 for performance.
|
||||||
|
posters: images.posters.slice(0, 12),
|
||||||
|
logos: images.logos.slice(0, 8),
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentImages = allImages[selectedCategory];
|
||||||
|
|
||||||
|
if (
|
||||||
|
!images.backdrops.length &&
|
||||||
|
!images.posters.length &&
|
||||||
|
!images.logos.length
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const openLightbox = (index: number) => {
|
||||||
|
setLightboxIndex(index);
|
||||||
|
setLightboxOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeLightbox = () => {
|
||||||
|
setLightboxOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextImage = () => {
|
||||||
|
setLightboxIndex((prev) => (prev + 1) % currentImages.length);
|
||||||
|
};
|
||||||
|
|
||||||
|
const prevImage = () => {
|
||||||
|
setLightboxIndex(
|
||||||
|
(prev) => (prev - 1 + currentImages.length) % currentImages.length
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getImageUrl = (path: string, size: string = "w500") => {
|
||||||
|
return `https://image.tmdb.org/t/p/${size}${path}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="py-16">
|
||||||
|
<div className="px-6 lg:px-8">
|
||||||
|
<div className="max-w-7xl mx-auto">
|
||||||
|
<div className="flex items-center gap-3 mb-8">
|
||||||
|
<div className="p-2 rounded-lg bg-gradient-to-r from-purple-500 to-pink-500">
|
||||||
|
<FaImages className="text-white" size={20} />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-3xl font-bold bg-gradient-to-r from-purple-400 to-pink-400 bg-clip-text text-transparent">
|
||||||
|
Galeria
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Category tabs */}
|
||||||
|
<div className="flex gap-4 mb-8">
|
||||||
|
{Object.entries(allImages).map(([category, categoryImages]) => {
|
||||||
|
if (!categoryImages.length) return null;
|
||||||
|
|
||||||
|
const labels = {
|
||||||
|
backdrops: "Kadry",
|
||||||
|
posters: "Plakaty",
|
||||||
|
logos: "Loga",
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={category}
|
||||||
|
onClick={() =>
|
||||||
|
setSelectedCategory(category as keyof typeof allImages)
|
||||||
|
}
|
||||||
|
className={`px-6 py-3 rounded-xl font-medium transition-all duration-300 ${
|
||||||
|
selectedCategory === category
|
||||||
|
? "bg-gradient-to-r from-purple-600 to-pink-600 text-white shadow-lg"
|
||||||
|
: "bg-white/10 text-gray-300 hover:bg-white/20 hover:text-white"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{labels[category as keyof typeof labels]} (
|
||||||
|
{categoryImages.length})
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Image grid */}
|
||||||
|
<div
|
||||||
|
className={`grid gap-4 ${
|
||||||
|
selectedCategory === "backdrops"
|
||||||
|
? "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
|
||||||
|
: selectedCategory === "posters"
|
||||||
|
? "grid-cols-2 md:grid-cols-4 lg:grid-cols-6"
|
||||||
|
: "grid-cols-2 md:grid-cols-3 lg:grid-cols-4"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{currentImages.map((image, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="group relative overflow-hidden rounded-xl cursor-pointer bg-slate-800"
|
||||||
|
onClick={() => openLightbox(index)}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={getImageUrl(
|
||||||
|
image.file_path,
|
||||||
|
selectedCategory === "backdrops" ? "w780" : "w342"
|
||||||
|
)}
|
||||||
|
alt={`${movieTitle} - ${selectedCategory}`}
|
||||||
|
className="w-full h-full object-cover transition-all duration-500 group-hover:scale-110"
|
||||||
|
style={{
|
||||||
|
aspectRatio:
|
||||||
|
selectedCategory === "backdrops"
|
||||||
|
? "16/9"
|
||||||
|
: selectedCategory === "posters"
|
||||||
|
? "2/3"
|
||||||
|
: "auto",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||||
|
<div className="p-3 rounded-full bg-white/20 backdrop-blur-sm">
|
||||||
|
<FaImages className="text-white" size={20} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Lightbox */}
|
||||||
|
{lightboxOpen && (
|
||||||
|
<div className="fixed inset-0 z-50 bg-black/90 flex items-center justify-center p-4">
|
||||||
|
<div className="relative max-w-6xl max-h-full">
|
||||||
|
{/* Close button */}
|
||||||
|
<button
|
||||||
|
onClick={closeLightbox}
|
||||||
|
className="absolute top-4 right-4 z-10 p-2 rounded-full bg-black/50 text-white hover:bg-black/70 transition-colors"
|
||||||
|
>
|
||||||
|
<FaTimes size={20} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Navigation buttons */}
|
||||||
|
{currentImages.length > 1 && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
onClick={prevImage}
|
||||||
|
className="absolute left-4 top-1/2 -translate-y-1/2 z-10 p-3 rounded-full bg-black/50 text-white hover:bg-black/70 transition-colors"
|
||||||
|
>
|
||||||
|
<FaChevronLeft size={20} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={nextImage}
|
||||||
|
className="absolute right-4 top-1/2 -translate-y-1/2 z-10 p-3 rounded-full bg-black/50 text-white hover:bg-black/70 transition-colors"
|
||||||
|
>
|
||||||
|
<FaChevronRight size={20} />
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Image */}
|
||||||
|
<img
|
||||||
|
src={getImageUrl(
|
||||||
|
currentImages[lightboxIndex].file_path,
|
||||||
|
"original"
|
||||||
|
)}
|
||||||
|
alt={`${movieTitle} - ${selectedCategory}`}
|
||||||
|
className="max-w-full max-h-full object-contain rounded-lg"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Image counter */}
|
||||||
|
{currentImages.length > 1 && (
|
||||||
|
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 px-4 py-2 rounded-full bg-black/50 text-white text-sm">
|
||||||
|
{lightboxIndex + 1} / {currentImages.length}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Background click to close */}
|
||||||
|
<div className="absolute inset-0 -z-10" onClick={closeLightbox} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { SearchResult } from "@/lib/tmdb/types";
|
||||||
|
import { MovieCard } from "@/components/atoms/MovieCard";
|
||||||
|
import { FC, useState } from "react";
|
||||||
|
import { FaChevronLeft, FaChevronRight, FaStar } from "react-icons/fa";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
movies: SearchResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RecommendedMovies: FC<Props> = ({ movies }) => {
|
||||||
|
const [currentPage, setCurrentPage] = useState(0);
|
||||||
|
const moviesPerPage = 4;
|
||||||
|
const totalPages = Math.ceil(movies.results.length / moviesPerPage);
|
||||||
|
|
||||||
|
if (!movies.results.length) return null;
|
||||||
|
|
||||||
|
const currentMovies = movies.results.slice(
|
||||||
|
currentPage * moviesPerPage,
|
||||||
|
(currentPage + 1) * moviesPerPage
|
||||||
|
);
|
||||||
|
|
||||||
|
const nextPage = () => {
|
||||||
|
setCurrentPage((prev) => (prev + 1) % totalPages);
|
||||||
|
};
|
||||||
|
|
||||||
|
const prevPage = () => {
|
||||||
|
setCurrentPage((prev) => (prev - 1 + totalPages) % totalPages);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="py-16 bg-gradient-to-br from-slate-900/50 to-slate-800/50">
|
||||||
|
<div className="px-6 lg:px-8">
|
||||||
|
<div className="max-w-7xl mx-auto">
|
||||||
|
<div className="flex items-center justify-between mb-8">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="p-2 rounded-lg bg-gradient-to-r from-yellow-500 to-orange-500">
|
||||||
|
<FaStar className="text-white" size={20} />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-3xl font-bold bg-gradient-to-r from-yellow-400 to-orange-400 bg-clip-text text-transparent">
|
||||||
|
Polecane dla Ciebie
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<button
|
||||||
|
onClick={prevPage}
|
||||||
|
className="p-3 rounded-full bg-gradient-to-r from-yellow-500/20 to-orange-500/20 hover:from-yellow-500/30 hover:to-orange-500/30 text-white transition-all duration-300 border border-yellow-400/30"
|
||||||
|
>
|
||||||
|
<FaChevronLeft size={16} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={nextPage}
|
||||||
|
className="p-3 rounded-full bg-gradient-to-r from-yellow-500/20 to-orange-500/20 hover:from-yellow-500/30 hover:to-orange-500/30 text-white transition-all duration-300 border border-yellow-400/30"
|
||||||
|
>
|
||||||
|
<FaChevronRight size={16} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||||
|
{currentMovies.map((movie) => (
|
||||||
|
<MovieCard
|
||||||
|
key={movie.id}
|
||||||
|
layout="aurora"
|
||||||
|
id={movie.id}
|
||||||
|
title={movie.title}
|
||||||
|
overview={movie.overview}
|
||||||
|
poster_path={movie.poster_path}
|
||||||
|
release_date={movie.release_date}
|
||||||
|
vote_average={movie.vote_average}
|
||||||
|
popularity={movie.popularity}
|
||||||
|
adult={movie.adult}
|
||||||
|
backdrop_path={movie.backdrop_path}
|
||||||
|
genre_ids={movie.genre_ids.join(",")}
|
||||||
|
original_language={movie.original_language}
|
||||||
|
original_title={movie.original_title}
|
||||||
|
video={movie.video}
|
||||||
|
vote_count={movie.vote_count}
|
||||||
|
seen={false}
|
||||||
|
favorite={false}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="flex justify-center mt-8">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
{Array.from({ length: totalPages }, (_, i) => (
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
onClick={() => setCurrentPage(i)}
|
||||||
|
className={`w-3 h-3 rounded-full transition-all duration-300 ${
|
||||||
|
currentPage === i
|
||||||
|
? "bg-gradient-to-r from-yellow-500 to-orange-500 scale-110"
|
||||||
|
: "bg-white/30 hover:bg-white/50"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { SearchResult } from "@/lib/tmdb/types";
|
||||||
|
import { MovieCard } from "@/components/atoms/MovieCard";
|
||||||
|
import { FC, useState } from "react";
|
||||||
|
import { FaChevronLeft, FaChevronRight } from "react-icons/fa";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
movies: SearchResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SimilarMovies: FC<Props> = ({ movies }) => {
|
||||||
|
const [currentPage, setCurrentPage] = useState(0);
|
||||||
|
const moviesPerPage = 4;
|
||||||
|
const totalPages = Math.ceil(movies.results.length / moviesPerPage);
|
||||||
|
|
||||||
|
if (!movies.results.length) return null;
|
||||||
|
|
||||||
|
const currentMovies = movies.results.slice(
|
||||||
|
currentPage * moviesPerPage,
|
||||||
|
(currentPage + 1) * moviesPerPage
|
||||||
|
);
|
||||||
|
|
||||||
|
const nextPage = () => {
|
||||||
|
setCurrentPage((prev) => (prev + 1) % totalPages);
|
||||||
|
};
|
||||||
|
|
||||||
|
const prevPage = () => {
|
||||||
|
setCurrentPage((prev) => (prev - 1 + totalPages) % totalPages);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="py-16">
|
||||||
|
<div className="px-6 lg:px-8">
|
||||||
|
<div className="max-w-7xl mx-auto">
|
||||||
|
<div className="flex items-center justify-between mb-8">
|
||||||
|
<h2 className="text-3xl font-bold bg-gradient-to-r from-white to-gray-300 bg-clip-text text-transparent">
|
||||||
|
Podobne filmy
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<button
|
||||||
|
onClick={prevPage}
|
||||||
|
className="p-3 rounded-full bg-white/10 hover:bg-white/20 text-white transition-all duration-300 border border-white/20 hover:border-purple-400/50"
|
||||||
|
>
|
||||||
|
<FaChevronLeft size={16} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={nextPage}
|
||||||
|
className="p-3 rounded-full bg-white/10 hover:bg-white/20 text-white transition-all duration-300 border border-white/20 hover:border-purple-400/50"
|
||||||
|
>
|
||||||
|
<FaChevronRight size={16} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||||
|
{currentMovies.map((movie) => (
|
||||||
|
<MovieCard
|
||||||
|
key={movie.id}
|
||||||
|
layout="aurora"
|
||||||
|
id={movie.id}
|
||||||
|
title={movie.title}
|
||||||
|
overview={movie.overview}
|
||||||
|
poster_path={movie.poster_path}
|
||||||
|
release_date={movie.release_date}
|
||||||
|
vote_average={movie.vote_average}
|
||||||
|
popularity={movie.popularity}
|
||||||
|
adult={movie.adult}
|
||||||
|
backdrop_path={movie.backdrop_path}
|
||||||
|
genre_ids={movie.genre_ids.join(",")}
|
||||||
|
original_language={movie.original_language}
|
||||||
|
original_title={movie.original_title}
|
||||||
|
video={movie.video}
|
||||||
|
vote_count={movie.vote_count}
|
||||||
|
seen={false}
|
||||||
|
favorite={false}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="flex justify-center mt-8">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
{Array.from({ length: totalPages }, (_, i) => (
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
onClick={() => setCurrentPage(i)}
|
||||||
|
className={`w-3 h-3 rounded-full transition-all duration-300 ${
|
||||||
|
currentPage === i
|
||||||
|
? "bg-gradient-to-r from-purple-500 to-pink-500 scale-110"
|
||||||
|
: "bg-white/30 hover:bg-white/50"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue