Skip to content

Commit

Permalink
Merge pull request #12 from fabriciopgl/feature/1
Browse files Browse the repository at this point in the history
✨ Adiciona página de detalhes dos locais
  • Loading branch information
fabriciopgl authored Nov 27, 2024
2 parents 6bd4bac + cc3a107 commit e7e65c4
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 6 deletions.
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
NEXT_PUBLIC_GOOGLE_CLIENT_ID=xxxx
NEXT_PUBLIC_GOOGLE_USER_SCRIPT_URL=xxxx
NEXT_PUBLIC_GOOGLE_PLACES_SCRIPT_URL=xxxx
NEXT_PUBLIC_GOOGLE_PLACE_DETAILS_SCRIPT_URL=xxxx
NEXT_PUBLIC_GOOGLE_FAVORITE_PLACES_SCRIPT_URL=xxxx
1 change: 1 addition & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
NEXT_PUBLIC_GOOGLE_USER_SCRIPT_URL: ${{ secrets.GOOGLE_USER_SCRIPT_URL }}
NEXT_PUBLIC_GOOGLE_PLACES_SCRIPT_URL: ${{ secrets.GOOGLE_PLACES_SCRIPT_URL }}
NEXT_PUBLIC_GOOGLE_FAVORITE_PLACES_SCRIPT_URL: ${{ secrets.GOOGLE_FAVORITE_PLACES_SCRIPT_URL }}
NEXT_PUBLIC_GOOGLE_PLACE_DETAILS_SCRIPT_URL: ${{ secrets.GOOGLE_PLACE_DETAILS_SCRIPT_URL }}
run: yarn build

- name: Deploy to GitHub Pages
Expand Down
59 changes: 55 additions & 4 deletions app/detalhes/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,67 @@
"use client";
import Carousel from "@/components/Carousel";
import { usePlacesContext } from "@/contexts/PlacesContext";
import { Place, PlaceDetails } from "@/domains/Places/types";
import { useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
import { FaMapPin } from "react-icons/fa";

const PlaceDetails: React.FC = () => {
const PlaceDetailsComponent: React.FC = () => {
const [selectedPlace, setSelectedPlace] = useState<Place>();
const { places, placeDetails, loading, fetchPlaceDetails } =
usePlacesContext();
const searchParams = useSearchParams();
const placeId = searchParams.get("placeId");

useEffect(() => {
if (places.length > 0)
setSelectedPlace(places.find((p) => p.id === Number(placeId)));
}, [placeId, places]);

useEffect(() => {
const getDetails = async () => {
fetchPlaceDetails(placeId || "");
};

getDetails();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [placeId]);

return (
<div className="container mx-auto p-4">
<h1 className="text-4xl font-bold mb-4">{placeId}</h1>
<p>Teste</p>
<div className="relative h-[50vh] sm:h-[25vh] md:h-[30vh] lg:h-[40vh] xl:h-[50vh] portrait:h-[15vh] mb-8">
{loading ? (
// Skeleton loader enquanto os dados são carregados
<div className="w-full h-full bg-gray-200 animate-pulse rounded-lg">
<div className="w-full h-full bg-gray-300 rounded-lg"></div>
</div>
) : (
// Carousel real depois que os dados foram carregados
<Carousel images={placeDetails?.carouselImages || []} />
)}
</div>

{/* Nome do local */}
<h1 className="text-4xl font-bold mb-4">{selectedPlace?.name}</h1>

<div className="flex items-center space-x-2 mb-4">
<FaMapPin className="text-red-500" />
<span className="text-lg">{placeDetails?.location}</span>
</div>

{/* Descrição do local */}
<p className="text-lg mb-8">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sit
amet sapien eu ligula blandit consequat. Integer eget dolor in lacus
posuere volutpat.
</p>

{/* Mapa com a localização */}
{selectedPlace?.description && (
<div className="w-full h-[400px] mb-8"></div>
)}
</div>
);
};

export default PlaceDetails;
export default PlaceDetailsComponent;
72 changes: 72 additions & 0 deletions components/Carousel/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"use client";
import { useState } from "react";
import { FaChevronLeft, FaChevronRight } from "react-icons/fa";

const Carousel = ({ images }: { images: string[] }) => {
const [currentIndex, setCurrentIndex] = useState(0);

const goToNext = () => {
setCurrentIndex((prevIndex) => (prevIndex + 1) % images.length);
};

const goToPrevious = () => {
setCurrentIndex(
(prevIndex) => (prevIndex - 1 + images.length) % images.length
);
};

return (
<div>
{/* Imagens */}
<div className="absolute inset-0 overflow-hidden">
<div
className="flex transition-transform duration-500 ease-in-out"
style={{
transform: `translateX(-${currentIndex * 100}%)`,
}}
>
{images.map((image, index) => (
<div
key={index}
className="w-full h-full flex justify-center items-center flex-shrink-0"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={image}
alt={`Imagem ${index + 1}`}
className="w-full h-full object-contain"
/>
</div>
))}
</div>
</div>

<button
onClick={goToPrevious}
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-green-900 text-white p-2 rounded-full shadow-lg z-10"
>
<FaChevronLeft />
</button>
<button
onClick={goToNext}
className="absolute right-4 top-1/2 transform -translate-y-1/2 bg-green-900 text-white p-2 rounded-full shadow-lg z-10"
>
<FaChevronRight />
</button>

<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex space-x-2">
{images.map((_, index) => (
<div
key={index}
onClick={() => setCurrentIndex(index)}
className={`w-3 h-3 rounded-full bg-white cursor-pointer ${
currentIndex === index ? "bg-opacity-100" : "bg-opacity-50"
}`}
/>
))}
</div>
</div>
);
};

export default Carousel;
28 changes: 26 additions & 2 deletions contexts/PlacesContext.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
"use client";
import { Place } from "@/domains/Places/types";
import { Place, PlaceDetails } from "@/domains/Places/types";
import axios from "axios";
import React, { createContext, useContext, useEffect, useState } from "react";

interface PlacesContextType {
places: Place[];
loading: boolean;
error: string | null;
placeDetails: PlaceDetails | undefined;
fetchPlaceDetails: (placeId: string) => void;
}

const PlacesContext = createContext<PlacesContextType | undefined>(undefined);

const SCRIPT_URL = process.env.NEXT_PUBLIC_GOOGLE_PLACES_SCRIPT_URL!;
const PLACE_DETAILS_SCRIPT_URL =
process.env.NEXT_PUBLIC_GOOGLE_PLACE_DETAILS_SCRIPT_URL!;

export const PlacesProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [places, setPlaces] = useState<Place[]>([]);
const [placeDetails, setPlaceDetails] = useState<PlaceDetails | undefined>(
undefined
);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);

Expand All @@ -40,8 +48,24 @@ export const PlacesProvider: React.FC<{ children: React.ReactNode }> = ({
fetchPlaces();
}, []);

const fetchPlaceDetails = async (placeId: string) => {
try {
setLoading(true);
const response = await axios.get(
`${PLACE_DETAILS_SCRIPT_URL}?placeId=${placeId}`
);
setPlaceDetails(response.data[0]);
} catch (err: unknown) {
console.error("Error fetching place details");
} finally {
setLoading(false);
}
};

return (
<PlacesContext.Provider value={{ places, loading, error }}>
<PlacesContext.Provider
value={{ places, placeDetails, loading, error, fetchPlaceDetails }}
>
{children}
</PlacesContext.Provider>
);
Expand Down
9 changes: 9 additions & 0 deletions domains/Places/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,12 @@ export type Place = {
image: string;
type: PlaceType[];
};

interface CarouselImage {
carouselImages: string[];
}

export interface PlaceDetails extends CarouselImage {
placeId: string;
location: string;
}

0 comments on commit e7e65c4

Please sign in to comment.