1
1
import React , { useEffect , useState } from 'react'
2
2
import Navbar from '../components/Navbar'
3
3
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'
6
6
import calendar_svg from '../assets/SVG/calendar.svg'
7
7
import ruler_svg from '../assets/SVG/ruler.svg'
8
8
import weighing_scale_svg from '../assets/SVG/weighing_scale.svg'
9
9
import paw_svg from '../assets/SVG/paw.svg'
10
10
import axios from 'axios'
11
+ import LoadingScreen from '../components/LoadingScreen'
12
+ import AdditionalDetailCard from '../components/AdditionalDetailCard'
13
+ import { LoremIpsum } from 'lorem-ipsum'
11
14
12
15
const PetDetailPage : React . FC = ( ) => {
16
+ const [ m_isLoading , setIsLoading ] = useState < boolean > ( true )
13
17
const [ m_petApiData , setPetApiData ] = useState < PetApiData > ( )
14
18
const m_searchParams = useSearchParams ( ) [ 0 ]
19
+ const m_navTo = useNavigate ( )
15
20
16
21
useEffect ( ( ) => {
17
22
const pet_type = m_searchParams . get ( 'pet_type' )
@@ -50,6 +55,7 @@ const PetDetailPage: React.FC = () => {
50
55
pet_type === "dog" ? PET_API_TYPE . DOG : PET_API_TYPE . CAT
51
56
)
52
57
setPetApiData ( petApiData )
58
+ setIsLoading ( false )
53
59
}
54
60
catch ( err : any ) {
55
61
console . log ( "Error fetching from Pet API: " , err . message )
@@ -64,31 +70,50 @@ const PetDetailPage: React.FC = () => {
64
70
info : string
65
71
}
66
72
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
+
67
93
const getAdditionalInfo = ( petApiData : PetApiData ) : PetAttribute [ ] => {
94
+
68
95
switch ( petApiData . apiType ) {
69
96
case PET_API_TYPE . DOG :
70
97
const dogBreedData = petApiData . breedData as DogBreedData
71
98
return [
99
+ { attribute : "Pet Type" , imgURL : paw_svg , info : "Dog" } ,
72
100
{ attribute : "Lifespan" , imgURL : calendar_svg , info : dogBreedData . lifespan } ,
73
101
{ attribute : "Height" , imgURL : ruler_svg , info : dogBreedData . height + " cm" } ,
74
- { attribute : "Temperament(s)" , imgURL : paw_svg , info : dogBreedData . temperaments . toString ( ) } ,
75
102
{ attribute : "Weight" , imgURL : weighing_scale_svg , info : dogBreedData . weight + " kg" } ,
76
103
]
77
104
case PET_API_TYPE . CAT :
78
105
const catBreedData = petApiData . breedData as CatBreedData
79
106
return [
107
+ { attribute : "Pet Type" , imgURL : paw_svg , info : "Cat" } ,
80
108
{ attribute : "Lifespan" , imgURL : calendar_svg , info : catBreedData . lifespan + " years" } ,
81
- { attribute : "Temperament(s)" , imgURL : paw_svg , info : catBreedData . temperaments . toString ( ) } ,
82
109
{ attribute : "Weight" , imgURL : weighing_scale_svg , info : catBreedData . weight + " kg" }
83
110
]
84
111
default :
85
112
return [ ]
86
113
}
87
114
}
88
115
89
- useEffect ( ( ) => {
90
- console . log ( "Pet api data change: " , m_petApiData )
91
- } , [ m_petApiData ] )
116
+ if ( m_isLoading ) { return < LoadingScreen /> }
92
117
93
118
return (
94
119
< main >
@@ -104,12 +129,13 @@ const PetDetailPage: React.FC = () => {
104
129
} } className = 'w-full h-96 mb-margin-xl' > </ div >
105
130
106
131
{ /* --- BODY (constrained width) --- */ }
107
- < div className = 'max-w-6xl mx-margin-l' >
132
+ < div className = 'max-w-7xl mx-margin-l' >
108
133
109
134
{ /* --- BODY (Description + Adoption Fee Box) ---- */ }
110
135
< div className = 'flex flex-col md:flex-row' >
136
+
111
137
{ /* --- 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 ' >
113
139
114
140
{ /* ---- DESC HEADER ---- */ }
115
141
< 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 = () => {
121
147
`${ ( m_petApiData . breedData as CatBreedData ) . description } `
122
148
} </ p >
123
149
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
+
124
170
{ /* ---- PET ATTRIBUTES/INFO ----- */ }
125
171
< div className = '' > {
126
- getAdditionalInfo ( m_petApiData ) . map ( iconInfoPair => {
172
+ getAdditionalInfo ( m_petApiData ) . map ( ( petAttrib , idx ) => {
127
173
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 >
132
179
</ div >
133
180
)
134
181
} )
@@ -143,26 +190,28 @@ const PetDetailPage: React.FC = () => {
143
190
{ /* ---- ADDITIONAL DETAILS ----- */ }
144
191
< div >
145
192
< 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 >
154
203
</ div >
155
204
</ div >
156
205
157
206
{ /* ----- ADOPTION FEE BOX ----- */ }
158
207
< div className = '
159
208
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
161
210
' >
162
211
< span className = 'text-xl font-medium mb-margin-m' > Adoption Fee</ span >
163
212
< span className = 'text-3xl font-semibold mb-margin-xs' > $150.0</ span >
164
213
< 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 = '
166
215
text-text-950 font-semibold bg-accent-500 text-lg
167
216
hover:bg-accent-600 min-w-64 py-3 rounded-xl transition-colors duration-200
168
217
' > ADOPT ME</ button >
0 commit comments