Skip to content

Commit 9e453fc

Browse files
Bunch of errors in retrieving the pet information for the pet detail page - will fix this later
1 parent 1891730 commit 9e453fc

12 files changed

+540
-82
lines changed

package-lock.json

Lines changed: 396 additions & 50 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"react": "^18.3.1",
1717
"react-dom": "^18.3.1",
1818
"react-intersection-observer": "^9.13.1",
19-
"react-router-dom": "^6.27.0"
19+
"react-router-dom": "^6.27.0",
20+
"react-select": "^5.8.2"
2021
},
2122
"devDependencies": {
2223
"@eslint/js": "^9.13.0",

src/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import HomePage from './pages/HomePage'
33
import AuthPage from './pages/AuthPage'
44
import { ROUTE_URL } from './others/Globals'
55
import AdoptionGalleryPage from './pages/AdoptionGalleryPage'
6+
import PetDetailPage from './pages/PetDetailPage'
67

78
const browserRouter = createBrowserRouter([
89
{ path: ROUTE_URL.HOME, element: <HomePage /> },
910
{ path: ROUTE_URL.AUTH, element: <AuthPage /> },
10-
{ path: ROUTE_URL.GALLERY, element: <AdoptionGalleryPage /> }
11+
{ path: ROUTE_URL.GALLERY, element: <AdoptionGalleryPage /> },
12+
{ path: ROUTE_URL.PET_DETAIL, element: <PetDetailPage /> }
1113
])
1214

1315
const App: React.FC = () => {

src/assets/SVG/search.svg

Lines changed: 1 addition & 1 deletion
Loading

src/common/AppContext.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { createContext, Dispatch, ReactNode, useEffect, useState } from "react";
2+
import { PetApiData } from "../others/Globals";
3+
4+
// Any general information you want to be globally accessible
5+
// just put it within this context
6+
interface AppContextType {
7+
petApiData: PetApiData | null
8+
setAppContext: Dispatch<React.SetStateAction<AppContextType>> | null
9+
}
10+
11+
export const AppContext = createContext<AppContextType | null>(null)
12+
13+
const AppContextProvider: React.FC<{ children: ReactNode }> = props => {
14+
const [m_contextData, setContextData] = useState<AppContextType>({
15+
petApiData: null,
16+
setAppContext: null
17+
})
18+
19+
useEffect(() => {
20+
setContextData(oldCtx => {
21+
const newCtx = { ...oldCtx }
22+
newCtx.setAppContext = setContextData
23+
return newCtx
24+
})
25+
}, [])
26+
27+
return (
28+
<AppContext.Provider value={m_contextData}>
29+
{props.children}
30+
</AppContext.Provider>
31+
)
32+
}
33+
34+
export default AppContextProvider

src/common/AuthContext.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { User as FirebaseUser, onAuthStateChanged } from 'firebase/auth'
2-
import React, { createContext, useEffect, useState } from 'react'
2+
import React, { createContext, ReactNode, useEffect, useState } from 'react'
33
import { firebaseAuth } from '../others/FirebaseConfig'
44

55
interface AuthContextType {
@@ -8,7 +8,7 @@ interface AuthContextType {
88

99
export const AuthContext = createContext<AuthContextType | null>(null)
1010

11-
const AuthContextProvider: React.FC<{ children: React.ReactNode }> = props => {
11+
const AuthContextProvider: React.FC<{ children: ReactNode }> = props => {
1212
const [m_authState, setAuthState] = useState<AuthContextType>({ firebaseUser: null })
1313

1414
useEffect(() => {

src/components/Navbar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ const Navbar: React.FC<NavbarProps> = props => {
6262
<Link className='hover:text-accent-600 transition-colors' to={ROUTE_URL.HOME}>Home</Link>
6363
<Link className='hover:text-accent-600 transition-colors' to={ROUTE_URL.ABOUT}>About</Link>
6464
<Link className='hover:text-accent-600 transition-colors' to={ROUTE_URL.CONTACT_US}>Contact Us</Link>
65-
<Link className='hover:text-accent-600 transition-colors' to={ROUTE_URL.AUTH}>Login</Link>
65+
<Link className='hover:text-accent-600 transition-colors' to={ROUTE_URL.GALLERY}>Adoption</Link>
6666
</nav>
6767
<Link className='
6868
hidden justify-center items-center bg-primary-500 px-7 h-10 rounded-lg
6969
md:flex hover:bg-primary-600 transition-colors
70-
' to={ROUTE_URL.GALLERY}>Adopt</Link>
70+
' to={ROUTE_URL.AUTH}>Login</Link>
7171
</header>
7272
)
7373
}

src/components/PetInfoCard.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
import React, { useState } from 'react'
22
import { PET_API_TYPE, PetApiData } from '../others/Globals'
3+
import { useNavigate } from 'react-router-dom'
34

45
const PetInfoCard: React.FC<{ petApiData: PetApiData }> = ({ petApiData }) => {
56
const [m_isHovered, setIsHovered] = useState<boolean>(false)
7+
8+
const navTo = useNavigate()
9+
10+
const cardClickHandler = () => {
11+
// console.log("PetINfoCard() - ID: ", petApiData.id)
12+
// console.log("PetInfoCard() - About to navigate to detail page...")
13+
const petType = petApiData.apiType === PET_API_TYPE.DOG ? "dog" : "cat"
14+
navTo(`/pet_detail/${petType}/${petApiData.id}`)
15+
}
616

717
return (
818
<div
919
onMouseEnter={() => setIsHovered(true)}
1020
onMouseLeave={() => setIsHovered(false)}
21+
onClick={cardClickHandler}
1122
className='my-3 relative cursor-pointer'
1223
>
1324
<img className='min-h-64 rounded-xl object-cover' src={petApiData.imgURL} alt="" />
1425
<div className='absolute top-0 bottom-0 left-0 right-0 flex justify-center items-end'>
1526
<div
16-
style={{
17-
height: m_isHovered ? "16rem" : "0rem",
27+
style={{
28+
height: m_isHovered ? "16rem" : "0rem",
1829
paddingBottom: m_isHovered ? "0.75rem" : "0rem"
1930
}}
2031
className='
@@ -27,7 +38,7 @@ const PetInfoCard: React.FC<{ petApiData: PetApiData }> = ({ petApiData }) => {
2738
{petApiData.breedData?.lifespan}
2839
{petApiData.apiType === PET_API_TYPE.CAT ? " years" : ""}
2940
</span>
30-
<span><strong>Weight: </strong>{petApiData.breedData?.weight} kg</span>
41+
<span><strong>Weight: </strong>{petApiData.breedData?.weight} kg</span>
3142
</div>
3243
</div>
3344
</div>

src/components/sections/HeroSection.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ const HeroSection: React.FC = () => {
4141
'>Adopt a Pet</button>
4242
<button className='
4343
border-2 border-primary-500 px-5 h-full rounded-lg
44-
hover:bg-primary-500 hover:text-text-50
45-
'>Learn More</button>
44+
hover:bg-primary-600 hover:text-text-950
45+
'>Donate</button>
4646
</div>
4747
</div>
4848
</div>

src/others/Globals.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export const ROUTE_URL = {
22
HOME: "/",
33
GALLERY: "/adoption_gallery",
4+
PET_DETAIL: "/pet_detail/:pet_type/:pet_id",
45
ABOUT: "/about",
56
CONTACT_US: "/contact_us",
67
AUTH: "/auth",

src/pages/AdoptionGalleryPage.tsx

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import axios from 'axios'
22
import React, { useEffect, useState } from 'react'
33
import { PET_API_TYPE, PetApiData, Utils } from '../others/Globals'
4+
import search_icon from '../assets/SVG/search.svg'
45
import Navbar from '../components/Navbar'
56
import PetInfoCard from '../components/PetInfoCard'
67
import FooterSection from '../components/sections/FooterSection'
8+
import Select from 'react-select'
79

810
const AdoptionGalleryPage: React.FC = () => {
911
const [m_petData, setPetData] = useState<PetApiData[]>([])
@@ -15,46 +17,62 @@ const AdoptionGalleryPage: React.FC = () => {
1517
try {
1618
const catApiRes = await axios.get(
1719
`https://api.thecatapi.com/v1/images/search?has_breeds=1&limit=${imageCount}`, {
18-
headers: { 'x-api-key': import.meta.env.VITE_CAT_API_KEY }
19-
}
20+
headers: { 'x-api-key': import.meta.env.VITE_CAT_API_KEY }
21+
}
2022
)
2123
const dogApiRes = await axios.get(
22-
`https://api.thedogapi.com/v1/images/search?has_breeds=1&limit=${imageCount}`, {
23-
headers: { 'x-api-key': import.meta.env.VITE_DOG_API_KEY
24+
`https://api.thedogapi.com/v1/images/search?has_breeds=1&limit=${imageCount}`, {
25+
headers: {
26+
'x-api-key': import.meta.env.VITE_DOG_API_KEY
2427
}
2528
})
2629

2730
const allPetData = [
2831
...catApiRes.data
29-
.map((obj: any) => Utils.convertToPetApiData(obj, PET_API_TYPE.CAT))
30-
.filter((petData: PetApiData) => !petData.imgURL.endsWith('.gif'))
32+
.map((obj: any) => Utils.convertToPetApiData(obj, PET_API_TYPE.CAT))
33+
.filter((petData: PetApiData) => !petData.imgURL.endsWith('.gif'))
3134
,
3235
...dogApiRes.data
33-
.map((obj: any) => Utils.convertToPetApiData(obj, PET_API_TYPE.DOG))
34-
.filter((petData: PetApiData) => !petData.imgURL.endsWith('.gif'))
36+
.map((obj: any) => Utils.convertToPetApiData(obj, PET_API_TYPE.DOG))
37+
.filter((petData: PetApiData) => !petData.imgURL.endsWith('.gif'))
3538
]
3639
Utils.durstenfeldShuffle(allPetData)
3740
setPetData(allPetData)
38-
console.log(allPetData)
3941
}
4042
catch (err: any) {
4143
console.error("Error fetching from API: ", err.message)
4244
}
4345
}
4446
fetchPetApiData(10)
4547
}, [])
46-
48+
49+
const petOptions = [
50+
{ value: 'dog', label: 'Cat' },
51+
{ value: 'cat', label: 'Dog' }
52+
]
53+
4754
return (
48-
<main>
55+
<main>
4956
<Navbar useSticky={true} />
50-
<section className='flex justify-start items-center px-4 py-3 gap-2'>
51-
<div className='text-center rounded-full px-6 py-3 bg-gray-300'>Le Option</div>
52-
<div className='text-center rounded-full px-6 py-3 bg-gray-300'>Le Option</div>
53-
<div className='text-center rounded-full px-6 py-3 bg-gray-300'>Le Option</div>
54-
<div className='text-center rounded-full px-6 py-3 bg-gray-300'>Le Option</div>
55-
<div className='text-center rounded-full px-6 py-3 bg-gray-300'>Le Option</div>
56-
<div className='text-center rounded-full px-6 py-3 bg-gray-300'>Le Option</div>
57+
<section className='flex justify-center items-center py-margin-l px-margin-s'>
58+
<div className='flex'>
59+
{/* ---- DROPDOWN CONTAINER ---- */}
60+
<div className='mr-margin-l'>
61+
<Select
62+
defaultValue={[petOptions[0], petOptions[1]]}
63+
options={petOptions} isMulti={true}
64+
/>
65+
</div>
66+
67+
{/* ---- SEARCH BAR ----- */}
68+
<div className='flex justify-start items-center bg-gray-200 w-48 h-11 px-3 py-2 rounded-lg'>
69+
<img className='w-7 h-7 mr-margin-xs' src={search_icon} alt="" />
70+
<input className='bg-transparent w-full focus:outline-none' type="text" />
71+
</div>
72+
</div>
73+
5774
</section>
75+
5876
<section className='min-h-96 flex justify-center items-center'>
5977
<div className='max-w-6xl mx-margin-s columns-2 md:columns-3 2xl:columns-4 my-margin-l'>{
6078
m_petData.map(data => {

src/pages/PetDetailPage.tsx

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,57 @@
1-
import React from 'react'
1+
import React, { useContext, useEffect, useState } from 'react'
22
import Navbar from '../components/Navbar'
33
import FooterSection from '../components/sections/FooterSection'
4+
import { useParams } from 'react-router-dom'
5+
import { PET_API_TYPE, PetApiData, Utils } from '../others/Globals'
6+
import axios from 'axios'
7+
import { AppContext } from '../common/AppContext'
48

59
const PetDetailPage: React.FC = () => {
10+
const { pet_type, pet_id } = useParams()
11+
const [m_petApiData, setPetApiData] = useState<PetApiData | null>(null)
12+
13+
useEffect(() => {
14+
console.log("Param info - pet type: ", pet_type)
15+
console.log("Param info - pet id: ", pet_id)
16+
17+
const endpointURL = pet_type === "dog" ?
18+
`https://api.thecatapi.com/v1/images/search?has_breeds=1&id=${pet_id}` :
19+
`https://api.thedogapi.com/v1/images/search?has_breeds=1&id=${pet_id}`
20+
21+
const fetchPetApiData = async(): Promise<void> => {
22+
try {
23+
const res = await axios.get(endpointURL, {
24+
headers: {
25+
'x-api-key': pet_type === 'dog' ?
26+
import.meta.env.VITE_DOG_API_KEY :
27+
import.meta.env.VITE_CAT_API_KEY
28+
}
29+
})
30+
console.log("Results from APi: ", res.data)
31+
setPetApiData(
32+
Utils.convertToPetApiData(
33+
res.data[0],
34+
pet_type === "dog" ? PET_API_TYPE.DOG : PET_API_TYPE.CAT
35+
)
36+
)
37+
}
38+
catch (err: any) {
39+
console.log("Error fetching from Pet API: ", err.message)
40+
}
41+
}
42+
fetchPetApiData()
43+
}, [])
44+
45+
useEffect(() => {
46+
console.log("Pet api data change: ", m_petApiData)
47+
}, [m_petApiData])
48+
649
return (
750
<main>
851
<Navbar />
9-
<section></section>
52+
<section className='min-h-[30rem] text-center'>
53+
{/* You are on the pet detail page. Pet ID: {} */}
54+
</section>
1055
<FooterSection />
1156
</main>
1257
)

0 commit comments

Comments
 (0)