Skip to content

Commit 51d6359

Browse files
More work (again) on the pet detail page - linked to the "checkout" page
1 parent bc7f15a commit 51d6359

10 files changed

+161
-30
lines changed

package-lock.json

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

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"axios": "^1.7.7",
1414
"firebase": "^11.0.1",
1515
"framer-motion": "^11.11.11",
16+
"lorem-ipsum": "^2.0.8",
1617
"react": "^18.3.1",
1718
"react-dom": "^18.3.1",
1819
"react-intersection-observer": "^9.13.1",

src/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import AuthPage from './pages/AuthPage'
44
import { ROUTE_URL } from './others/Globals'
55
import AdoptionGalleryPage from './pages/AdoptionGalleryPage'
66
import PetDetailPage from './pages/PetDetailPage'
7+
import CheckoutPage from './pages/CheckoutPage'
78

89
const browserRouter = createBrowserRouter([
910
{ path: ROUTE_URL.HOME, element: <HomePage /> },
1011
{ path: ROUTE_URL.AUTH, element: <AuthPage /> },
1112
{ path: ROUTE_URL.GALLERY, element: <AdoptionGalleryPage /> },
12-
{ path: ROUTE_URL.PET_DETAIL, element: <PetDetailPage /> }
13+
{ path: ROUTE_URL.PET_DETAIL, element: <PetDetailPage /> },
14+
{ path: ROUTE_URL.CHECKOUT, element: <CheckoutPage /> }
1315
])
1416

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

src/assets/SVG/child_friendly.svg

Lines changed: 1 addition & 0 deletions
Loading

src/common/AuthContext.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const AuthContextProvider: React.FC<{ children: ReactNode }> = props => {
1414
useEffect(() => {
1515
const unsubscribe = onAuthStateChanged(firebaseAuth, newFirebaserUser => {
1616
setAuthState({ firebaseUser: newFirebaserUser })
17-
console.log("AuthContextProvider - firebaserUser: ", newFirebaserUser)
17+
// console.log("AuthContextProvider - firebaserUser: ", newFirebaserUser)
1818
})
1919
return () => unsubscribe()
2020
}, [])
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react'
2+
3+
interface AdditionalDetailCardProps {
4+
imgURL: string
5+
attribute: string
6+
detail: string
7+
}
8+
9+
const AdditionalDetailCard: React.FC<AdditionalDetailCardProps> = props => {
10+
return (
11+
<div className='
12+
flex flex-col justify-start items-start outline outline-1 outline-gray-200
13+
w-full min-h-44 bg-white rounded-lg shadow-lg pl-8 pt-8
14+
'>
15+
<img className='w-9 mb-margin-l' src={props.imgURL} alt="" />
16+
<span className='font-semibold text-text-50 text-lg'><strong>{props.attribute}</strong></span>
17+
<span className='font-medium text-text-100 text-base'>{props.detail}</span>
18+
</div>
19+
)
20+
}
21+
22+
export default AdditionalDetailCard

src/components/LoadingScreen.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react'
2+
3+
const LoadingScreen: React.FC = () => {
4+
return (
5+
<div className='
6+
fixed top-0 left-0 right-0 bottom-0 bg-purple-500
7+
flex justify-center items-center
8+
'>
9+
<span>Loading screen.....</span>
10+
</div>
11+
)
12+
}
13+
14+
export default LoadingScreen

src/others/Globals.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export const ROUTE_URL = {
22
HOME: "/",
33
GALLERY: "/adoption_gallery",
44
PET_DETAIL: "/pet_detail",
5+
CHECKOUT: "/checkout",
56
ABOUT: "/about",
67
CONTACT_US: "/contact_us",
78
AUTH: "/auth",
@@ -10,7 +11,7 @@ export const ROUTE_URL = {
1011

1112
export enum PET_API_TYPE { DOG, CAT }
1213

13-
export class BreedData {
14+
export class BreedData {
1415
breed_id: string
1516
breed: string
1617
lifespan: string
@@ -107,9 +108,9 @@ export const Utils = {
107108
)
108109
},
109110
durstenfeldShuffle(arr: any[]): void {
110-
for (var i = arr.length - 1; i >= 0; i--) {
111-
var j = Math.floor(Math.random() * (i + 1));
112-
var temp = arr[i];
111+
for (let i = arr.length - 1; i >= 0; i--) {
112+
const j = Math.floor(Math.random() * (i + 1));
113+
const temp = arr[i];
113114
arr[i] = arr[j];
114115
arr[j] = temp;
115116
}

src/pages/CheckoutPage.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from 'react'
2+
import Navbar from '../components/Navbar'
3+
import FooterSection from '../components/sections/FooterSection'
4+
5+
const CheckoutPage: React.FC = () => {
6+
return (
7+
<main>
8+
<Navbar />
9+
<div>Check-out Page</div>
10+
<FooterSection />
11+
</main>
12+
)
13+
}
14+
15+
export default CheckoutPage

src/pages/PetDetailPage.tsx

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
import React, { useEffect, useState } from 'react'
22
import Navbar from '../components/Navbar'
33
import FooterSection from '../components/sections/FooterSection'
4-
import { CatBreedData, DogBreedData, PET_API_TYPE, PetApiData } from '../others/Globals'
5-
import { useSearchParams } from 'react-router-dom'
4+
import { CatBreedData, DogBreedData, PET_API_TYPE, PetApiData, ROUTE_URL, Utils } from '../others/Globals'
5+
import { useNavigate, useSearchParams } from 'react-router-dom'
66
import calendar_svg from '../assets/SVG/calendar.svg'
77
import ruler_svg from '../assets/SVG/ruler.svg'
88
import weighing_scale_svg from '../assets/SVG/weighing_scale.svg'
99
import paw_svg from '../assets/SVG/paw.svg'
1010
import axios from 'axios'
11+
import LoadingScreen from '../components/LoadingScreen'
12+
import AdditionalDetailCard from '../components/AdditionalDetailCard'
13+
import { LoremIpsum } from 'lorem-ipsum'
1114

1215
const PetDetailPage: React.FC = () => {
16+
const [m_isLoading, setIsLoading] = useState<boolean>(true)
1317
const [m_petApiData, setPetApiData] = useState<PetApiData>()
1418
const m_searchParams = useSearchParams()[0]
19+
const m_navTo = useNavigate()
1520

1621
useEffect(() => {
1722
const pet_type = m_searchParams.get('pet_type')
@@ -50,6 +55,7 @@ const PetDetailPage: React.FC = () => {
5055
pet_type === "dog" ? PET_API_TYPE.DOG : PET_API_TYPE.CAT
5156
)
5257
setPetApiData(petApiData)
58+
setIsLoading(false)
5359
}
5460
catch (err: any) {
5561
console.log("Error fetching from Pet API: ", err.message)
@@ -64,31 +70,50 @@ const PetDetailPage: React.FC = () => {
6470
info: string
6571
}
6672

73+
// const formatTemperaments = (temperaments: string[]): string => {
74+
// const MAX_LENGTH = 30
75+
// let displayStr = ""
76+
//
77+
// for (let i = 0; i < temperaments.length; i++) {
78+
// const newStr = displayStr + temperaments[i]
79+
// if (newStr.length > MAX_LENGTH) {
80+
// displayStr.padEnd(MAX_LENGTH, ".")
81+
// console.log(displayStr)
82+
// return displayStr
83+
// }
84+
// displayStr = newStr
85+
// if (i < temperaments.length - 1) {
86+
// displayStr += ", "
87+
// }
88+
// }
89+
// console.log(displayStr)
90+
// return displayStr
91+
// }
92+
6793
const getAdditionalInfo = (petApiData: PetApiData): PetAttribute[] => {
94+
6895
switch (petApiData.apiType) {
6996
case PET_API_TYPE.DOG:
7097
const dogBreedData = petApiData.breedData as DogBreedData
7198
return [
99+
{ attribute: "Pet Type", imgURL: paw_svg, info: "Dog" },
72100
{ attribute: "Lifespan", imgURL: calendar_svg, info: dogBreedData.lifespan },
73101
{ attribute: "Height", imgURL: ruler_svg, info: dogBreedData.height + " cm" },
74-
{ attribute: "Temperament(s)", imgURL: paw_svg, info: dogBreedData.temperaments.toString() },
75102
{ attribute: "Weight", imgURL: weighing_scale_svg, info: dogBreedData.weight + " kg" },
76103
]
77104
case PET_API_TYPE.CAT:
78105
const catBreedData = petApiData.breedData as CatBreedData
79106
return [
107+
{ attribute: "Pet Type", imgURL: paw_svg, info: "Cat" },
80108
{ attribute: "Lifespan", imgURL: calendar_svg, info: catBreedData.lifespan + " years" },
81-
{ attribute: "Temperament(s)", imgURL: paw_svg, info: catBreedData.temperaments.toString() },
82109
{ attribute: "Weight", imgURL: weighing_scale_svg, info: catBreedData.weight + " kg" }
83110
]
84111
default:
85112
return []
86113
}
87114
}
88115

89-
useEffect(() => {
90-
console.log("Pet api data change: ", m_petApiData)
91-
}, [m_petApiData])
116+
if (m_isLoading) { return <LoadingScreen /> }
92117

93118
return (
94119
<main>
@@ -104,12 +129,13 @@ const PetDetailPage: React.FC = () => {
104129
}} className='w-full h-96 mb-margin-xl'></div>
105130

106131
{/* --- BODY (constrained width) --- */}
107-
<div className='max-w-6xl mx-margin-l'>
132+
<div className='max-w-7xl mx-margin-l'>
108133

109134
{/* --- BODY (Description + Adoption Fee Box) ---- */}
110135
<div className='flex flex-col md:flex-row'>
136+
111137
{/* --- DESCRIPTION CONTAINER --- */}
112-
<div className='text-center flex-col items-start min-w-96 mb-margin-xl mr-margin-xl'>
138+
<div className='text-center flex-col items-start min-w-96 mb-margin-xl mr-margin-l'>
113139

114140
{/* ---- DESC HEADER ---- */}
115141
<h1 className='font-bold text-3xl text-left mb-margin-xxs'>{m_petApiData.breedData?.breed.toUpperCase()}</h1>
@@ -121,14 +147,35 @@ const PetDetailPage: React.FC = () => {
121147
`${(m_petApiData.breedData as CatBreedData).description}`
122148
}</p>
123149

150+
{
151+
(() => {
152+
const numParagraphs = Utils.randInt(1, 4)
153+
for (let i = 0; i < numParagraphs; i++) {
154+
return (
155+
<p className='text-left mb-margin-l text-lg'>{
156+
new LoremIpsum().generateParagraphs(Utils.randInt(1, 3))
157+
}</p>
158+
)
159+
}
160+
return <></>
161+
})()
162+
}
163+
<p className='text-left mb-margin-l text-lg'>{
164+
new LoremIpsum({
165+
sentencesPerParagraph: { min: 2, max: 5 },
166+
wordsPerSentence: { min: 4, max: 16 }
167+
}).generateParagraphs(Utils.randInt(1, 3))
168+
}</p>
169+
124170
{/* ---- PET ATTRIBUTES/INFO ----- */}
125171
<div className=''>{
126-
getAdditionalInfo(m_petApiData).map(iconInfoPair => {
172+
getAdditionalInfo(m_petApiData).map((petAttrib, idx) => {
127173
return (
128-
<div className='flex justify-start items-center mb-margin-m'>
129-
<img className='w-7 mr-margin-s' src={iconInfoPair.imgURL} alt="" />
130-
<span className='mr-text-xxs'><strong>{iconInfoPair.attribute}</strong></span>
131-
<span className='text-left'>{iconInfoPair.info}</span>
174+
<div key={idx} className='flex justify-start items-center mb-margin-m'>
175+
<img className='w-7 mr-margin-s' src={petAttrib.imgURL} alt="" />
176+
<span className='mr-text-xxs'><strong>{petAttrib.attribute}</strong></span>
177+
<span className='mr-margin-xs'><strong></strong></span>
178+
<span className='text-left font-medium text-text-200'>{petAttrib.info}</span>
132179
</div>
133180
)
134181
})
@@ -143,26 +190,28 @@ const PetDetailPage: React.FC = () => {
143190
{/* ---- ADDITIONAL DETAILS ----- */}
144191
<div>
145192
<h2 className='text-left text-2xl font-medium mb-text-xs'>Additional Details</h2>
146-
<div className='grid grid-cols-3 gap-4'>
147-
<div className='w-full h-32 bg-white rounded-lg shadow-lg'></div>
148-
<div className='w-full h-32 bg-white rounded-lg shadow-lg'></div>
149-
<div className='w-full h-32 bg-white rounded-lg shadow-lg'></div>
150-
<div className='w-full h-32 bg-white rounded-lg shadow-lg'></div>
151-
<div className='w-full h-32 bg-white rounded-lg shadow-lg'></div>
152-
<div className='w-full h-32 bg-white rounded-lg shadow-lg'></div>
153-
</div>
193+
<div className='grid grid-cols-2 lg:grid-cols-2 gap-4'>{
194+
getAdditionalInfo(m_petApiData).map((petAttrib, idx) => {
195+
return (
196+
<AdditionalDetailCard
197+
key={idx} imgURL={petAttrib.imgURL}
198+
attribute={petAttrib.attribute} detail={petAttrib.info}
199+
/>
200+
)
201+
})
202+
}</div>
154203
</div>
155204
</div>
156205

157206
{/* ----- ADOPTION FEE BOX ----- */}
158207
<div className='
159208
flex flex-col justify-center items-center rounded-xl shadow-lg
160-
h-60 max-w-96 text-center text-text-50 bg-white px-8
209+
h-60 w-full md:max-w-96 text-center text-text-50 bg-white px-8 mb-margin-l
161210
'>
162211
<span className='text-xl font-medium mb-margin-m'>Adoption Fee</span>
163212
<span className='text-3xl font-semibold mb-margin-xs'>$150.0</span>
164213
<span className='text-sm font-light mb-margin-m'>Give a pet a home</span>
165-
<button className='
214+
<button onClick={() => { m_navTo(ROUTE_URL.CHECKOUT) }} className='
166215
text-text-950 font-semibold bg-accent-500 text-lg
167216
hover:bg-accent-600 min-w-64 py-3 rounded-xl transition-colors duration-200
168217
'>ADOPT ME</button>

0 commit comments

Comments
 (0)