@rileybathurst/paddle 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -3
- package/package.json +2 -1
- package/src/PaddleBrandList.tsx +17 -10
- package/src/PaddleLocationCard.tsx +289 -114
- package/src/PaddleLocationDeck.tsx +10 -5
- package/src/PaddleSEO.tsx +40 -24
- package/src/PaddleTestimonial.tsx +22 -14
- package/src/PaddleTestimonials.tsx +7 -7
- package/src/PaddleTicket.tsx +43 -27
- package/src/phone.tsx +9 -14
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rileybathurst/paddle",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "vite",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"react-markdown": "^10.1.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
+
"@biomejs/biome": "2.0.2",
|
|
26
27
|
"@chromatic-com/storybook": "^4.0.0",
|
|
27
28
|
"@faker-js/faker": "^9.8.0",
|
|
28
29
|
"@storybook/addon-docs": "^9.0.11",
|
package/src/PaddleBrandList.tsx
CHANGED
|
@@ -23,18 +23,25 @@ type BrandListTypes = {
|
|
|
23
23
|
const PaddleBrandList = ({ nodes, sport }: BrandListTypes) => {
|
|
24
24
|
|
|
25
25
|
const BrandSet = new Set();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
let BrandArray = [];
|
|
27
|
+
|
|
28
|
+
if (sport) {
|
|
29
|
+
nodes.map((brand) => {
|
|
30
|
+
brand.retail.map((retail) => {
|
|
31
|
+
|
|
32
|
+
if (retail.sport.slug === sport) {
|
|
33
|
+
BrandSet.add(brand);
|
|
34
|
+
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
return BrandSet;
|
|
37
|
+
})
|
|
38
|
+
});
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
BrandArray = (Array.from(BrandSet));
|
|
41
|
+
} else {
|
|
42
|
+
// TODO: this needs a check if anything is published in the brand if no sport is passed
|
|
43
|
+
BrandArray = (Array.from(nodes));
|
|
44
|
+
}
|
|
38
45
|
|
|
39
46
|
return (
|
|
40
47
|
<ul className='brand_list'>
|
|
@@ -1,9 +1,46 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Link } from
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { Link } from "gatsby";
|
|
3
3
|
import Markdown from "react-markdown";
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
import HourMin from "./hour-min";
|
|
6
6
|
import Phone from "./phone";
|
|
7
|
+
import type { PaddleLocationCardTypes } from "./types/location-card-types";
|
|
8
|
+
|
|
9
|
+
// merged types are possible to dry this up but its also a lot
|
|
10
|
+
// type UpdatedUser = Merge<User, Updates>;
|
|
11
|
+
type PlaceTypes = {
|
|
12
|
+
commonName?: string;
|
|
13
|
+
streetAddress?: string;
|
|
14
|
+
addressLocality?: string;
|
|
15
|
+
addressRegion?: string;
|
|
16
|
+
postalCode?: string;
|
|
17
|
+
};
|
|
18
|
+
const Place = ({ commonName, streetAddress, addressLocality, addressRegion, postalCode }: PlaceTypes) => {
|
|
19
|
+
return (
|
|
20
|
+
<address>
|
|
21
|
+
{commonName ? (
|
|
22
|
+
<span>
|
|
23
|
+
{commonName}
|
|
24
|
+
<br />
|
|
25
|
+
</span>
|
|
26
|
+
) : null}
|
|
27
|
+
{streetAddress ? (
|
|
28
|
+
<span>
|
|
29
|
+
{streetAddress}
|
|
30
|
+
<br />
|
|
31
|
+
</span>
|
|
32
|
+
) : null}
|
|
33
|
+
{addressLocality ? <span>{addressLocality}, </span> : null}
|
|
34
|
+
{addressRegion ? <span>{addressRegion} </span> : null}
|
|
35
|
+
{postalCode ? (
|
|
36
|
+
<span>
|
|
37
|
+
{postalCode}
|
|
38
|
+
<br />
|
|
39
|
+
</span>
|
|
40
|
+
) : null}
|
|
41
|
+
</address>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
7
44
|
|
|
8
45
|
interface SeasonTypes {
|
|
9
46
|
season_start?: string;
|
|
@@ -14,10 +51,20 @@ interface SeasonTypes {
|
|
|
14
51
|
name: string;
|
|
15
52
|
offSeasonDetails?: string;
|
|
16
53
|
}
|
|
17
|
-
|
|
18
|
-
|
|
54
|
+
const Season = ({
|
|
55
|
+
name,
|
|
56
|
+
season_start,
|
|
57
|
+
season_end,
|
|
58
|
+
opening_time,
|
|
59
|
+
closing_time,
|
|
60
|
+
offSeasonDetails,
|
|
61
|
+
}: SeasonTypes) => {
|
|
19
62
|
// TODO: these need a query but thats not the most important first step
|
|
20
|
-
if (
|
|
63
|
+
if (
|
|
64
|
+
name === "Free Parking Lot" ||
|
|
65
|
+
name === "Parking" ||
|
|
66
|
+
name === "Delivery"
|
|
67
|
+
) {
|
|
21
68
|
return null;
|
|
22
69
|
}
|
|
23
70
|
|
|
@@ -29,119 +76,169 @@ function Season({ name, season_start, season_end, opening_time, closing_time, of
|
|
|
29
76
|
if (currentDay >= seasonStartDate && currentDay <= seasonEndDate) {
|
|
30
77
|
return (
|
|
31
78
|
<p>
|
|
32
|
-
{opening_time ? "Open Daily: " : null}
|
|
79
|
+
{opening_time ? "Open Daily: " : null}
|
|
80
|
+
<br />
|
|
33
81
|
{opening_time && closing_time ? (
|
|
34
|
-
<span
|
|
35
|
-
|
|
36
|
-
|
|
82
|
+
<span>
|
|
83
|
+
<HourMin time={opening_time} /> - <HourMin time={closing_time} />
|
|
84
|
+
</span>
|
|
85
|
+
) : null}
|
|
86
|
+
<br />
|
|
37
87
|
Weather Permitting
|
|
38
88
|
</p>
|
|
39
|
-
)
|
|
89
|
+
);
|
|
40
90
|
}
|
|
41
91
|
|
|
42
|
-
// outside of season
|
|
92
|
+
// * outside of season
|
|
43
93
|
return (
|
|
44
94
|
<div>
|
|
45
95
|
<p>We're closed for the season</p>
|
|
46
96
|
|
|
47
97
|
{currentDay < seasonStartDate ? (
|
|
48
98
|
<p>
|
|
49
|
-
We will reopen
|
|
50
|
-
|
|
99
|
+
We will reopen
|
|
100
|
+
<br />
|
|
101
|
+
{season_start}
|
|
102
|
+
<br />
|
|
51
103
|
Weather Permitting
|
|
52
104
|
</p>
|
|
53
105
|
) : null}
|
|
54
106
|
|
|
55
|
-
{offSeasonDetails ?
|
|
56
|
-
<p>{offSeasonDetails}</p>
|
|
57
|
-
) : null}
|
|
107
|
+
{offSeasonDetails ? <p>{offSeasonDetails}</p> : null}
|
|
58
108
|
</div>
|
|
59
|
-
)
|
|
109
|
+
);
|
|
60
110
|
}
|
|
61
111
|
|
|
62
|
-
// no season defaults to off season
|
|
63
|
-
// TODO: add some enum error messages here for if this is allowed to not have a season
|
|
112
|
+
// * no season defaults to off season
|
|
113
|
+
// TODO: v1.3 add some enum error messages here for if this is allowed to not have a season
|
|
64
114
|
return (
|
|
65
115
|
<div>
|
|
66
116
|
<p>We're closed for the season</p>
|
|
67
|
-
{offSeasonDetails ?
|
|
68
|
-
<p>{offSeasonDetails}</p>
|
|
69
|
-
) : null}
|
|
117
|
+
{offSeasonDetails ? <p>{offSeasonDetails}</p> : null}
|
|
70
118
|
</div>
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
}
|
|
119
|
+
);
|
|
120
|
+
};
|
|
74
121
|
|
|
75
122
|
interface ContentTypes {
|
|
123
|
+
link?: string;
|
|
76
124
|
svg: string;
|
|
77
125
|
name: string;
|
|
126
|
+
|
|
78
127
|
address: {
|
|
79
128
|
data: {
|
|
80
129
|
address: string;
|
|
81
|
-
}
|
|
130
|
+
};
|
|
82
131
|
};
|
|
132
|
+
|
|
83
133
|
description: {
|
|
84
134
|
data: {
|
|
85
135
|
description: string;
|
|
86
|
-
}
|
|
136
|
+
};
|
|
87
137
|
};
|
|
88
138
|
opening_time: string;
|
|
89
139
|
closing_time: string;
|
|
90
140
|
|
|
91
|
-
streetAddress?: string;
|
|
92
|
-
addressLocality?: string;
|
|
93
|
-
addressRegion?: string;
|
|
94
|
-
postalCode?: string;
|
|
95
|
-
commonName?: string;
|
|
96
|
-
|
|
97
141
|
season_start?: string;
|
|
98
142
|
season_end?: string;
|
|
99
143
|
|
|
100
144
|
offSeasonDetails?: string;
|
|
145
|
+
phone?: number;
|
|
101
146
|
|
|
147
|
+
streetAddress?: string;
|
|
148
|
+
addressLocality?: string;
|
|
149
|
+
addressRegion?: string;
|
|
150
|
+
postalCode?: string;
|
|
151
|
+
commonName?: string;
|
|
102
152
|
}
|
|
103
|
-
|
|
153
|
+
const PhoneContent = ({
|
|
154
|
+
link,
|
|
155
|
+
svg,
|
|
156
|
+
name,
|
|
157
|
+
address,
|
|
158
|
+
description,
|
|
159
|
+
opening_time,
|
|
160
|
+
closing_time,
|
|
161
|
+
streetAddress,
|
|
162
|
+
addressLocality,
|
|
163
|
+
addressRegion,
|
|
164
|
+
postalCode,
|
|
165
|
+
commonName,
|
|
166
|
+
season_start,
|
|
167
|
+
season_end,
|
|
168
|
+
offSeasonDetails,
|
|
169
|
+
phone,
|
|
170
|
+
}: ContentTypes) => {
|
|
104
171
|
return (
|
|
105
172
|
<>
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
173
|
+
{link?.includes("http") ? (
|
|
174
|
+
<a
|
|
175
|
+
href={link}
|
|
176
|
+
className="location"
|
|
177
|
+
target="_blank"
|
|
178
|
+
rel="noopener noreferrer"
|
|
179
|
+
title={name}
|
|
180
|
+
>
|
|
181
|
+
<div className="svg" dangerouslySetInnerHTML={{ __html: svg }} />
|
|
182
|
+
</a>
|
|
183
|
+
) : (
|
|
184
|
+
<Link to={link} className="location">
|
|
185
|
+
<div className="svg" dangerouslySetInnerHTML={{ __html: svg }} />
|
|
186
|
+
</Link>
|
|
187
|
+
)}
|
|
110
188
|
|
|
111
189
|
<div>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
{
|
|
119
|
-
{addressLocality ? <span>{addressLocality}, </span> : null}
|
|
120
|
-
{addressRegion ? <span>{addressRegion} </span> : null}
|
|
121
|
-
{postalCode ? <span>{postalCode}<br /></span> : null}
|
|
122
|
-
</address>
|
|
123
|
-
</>
|
|
124
|
-
) :
|
|
125
|
-
|
|
126
|
-
(<>
|
|
127
|
-
<h3 className="elbrus">{name}</h3>
|
|
128
|
-
|
|
129
|
-
<Markdown
|
|
130
|
-
components={{
|
|
131
|
-
div: ({ children, ...props }) => (
|
|
132
|
-
<div className="react-markdown" {...props}>
|
|
133
|
-
{children}
|
|
134
|
-
</div>
|
|
135
|
-
)
|
|
136
|
-
}}
|
|
190
|
+
<div className="multi_button">
|
|
191
|
+
{link?.includes("http") ? (
|
|
192
|
+
<a
|
|
193
|
+
href={link}
|
|
194
|
+
target="_blank"
|
|
195
|
+
rel="noopener noreferrer"
|
|
196
|
+
title={name}
|
|
137
197
|
>
|
|
138
|
-
{
|
|
139
|
-
</
|
|
140
|
-
|
|
198
|
+
<h3>{name}</h3>
|
|
199
|
+
</a>
|
|
200
|
+
) : (
|
|
201
|
+
<Link to={link} title={name}>
|
|
202
|
+
<h3>{name}</h3>
|
|
203
|
+
</Link>
|
|
204
|
+
)}
|
|
205
|
+
<Phone phone={phone} />
|
|
206
|
+
</div>
|
|
141
207
|
|
|
142
|
-
|
|
208
|
+
{streetAddress ||
|
|
209
|
+
addressLocality ||
|
|
210
|
+
addressRegion ||
|
|
211
|
+
postalCode ||
|
|
212
|
+
commonName ? (
|
|
213
|
+
|
|
214
|
+
link?.includes("http") ? (
|
|
215
|
+
<a
|
|
216
|
+
href={link}
|
|
217
|
+
target="_blank"
|
|
218
|
+
rel="noopener noreferrer"
|
|
219
|
+
title={name}
|
|
220
|
+
>
|
|
221
|
+
<Place
|
|
222
|
+
commonName={commonName}
|
|
223
|
+
streetAddress={streetAddress}
|
|
224
|
+
addressLocality={addressLocality}
|
|
225
|
+
addressRegion={addressRegion}
|
|
226
|
+
postalCode={postalCode}
|
|
227
|
+
/>
|
|
228
|
+
</a>
|
|
229
|
+
) : (
|
|
230
|
+
<Link to={link} title={name}>
|
|
231
|
+
<Place
|
|
232
|
+
commonName={commonName}
|
|
233
|
+
streetAddress={streetAddress}
|
|
234
|
+
addressLocality={addressLocality}
|
|
235
|
+
addressRegion={addressRegion}
|
|
236
|
+
postalCode={postalCode}
|
|
237
|
+
/>
|
|
238
|
+
</Link>
|
|
239
|
+
)
|
|
240
|
+
) : null}
|
|
143
241
|
|
|
144
|
-
<div>
|
|
145
242
|
{opening_time && closing_time ? (
|
|
146
243
|
<Season
|
|
147
244
|
season_start={season_start}
|
|
@@ -153,59 +250,122 @@ function Content({ svg, name, address, description, opening_time, closing_time,
|
|
|
153
250
|
/>
|
|
154
251
|
) : (
|
|
155
252
|
<div className="react-markdown">
|
|
156
|
-
|
|
157
|
-
{description.data.description}
|
|
158
|
-
</Markdown>
|
|
253
|
+
<Markdown>{description.data.description}</Markdown>
|
|
159
254
|
</div>
|
|
160
255
|
)}
|
|
161
256
|
</div>
|
|
162
257
|
</>
|
|
163
|
-
)
|
|
164
|
-
}
|
|
258
|
+
);
|
|
259
|
+
};
|
|
165
260
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
closing_time={closing_time}
|
|
261
|
+
const Content = ({
|
|
262
|
+
svg,
|
|
263
|
+
name,
|
|
264
|
+
address,
|
|
265
|
+
description,
|
|
266
|
+
opening_time,
|
|
267
|
+
closing_time,
|
|
268
|
+
streetAddress,
|
|
269
|
+
addressLocality,
|
|
270
|
+
addressRegion,
|
|
271
|
+
postalCode,
|
|
272
|
+
commonName,
|
|
273
|
+
season_start,
|
|
274
|
+
season_end,
|
|
275
|
+
offSeasonDetails,
|
|
276
|
+
}: ContentTypes) => {
|
|
277
|
+
return (
|
|
278
|
+
<>
|
|
279
|
+
<div className="svg" dangerouslySetInnerHTML={{ __html: svg }} />
|
|
186
280
|
|
|
281
|
+
<h3 className="elbrus">{name}</h3>
|
|
282
|
+
<div>
|
|
283
|
+
{streetAddress ||
|
|
284
|
+
addressLocality ||
|
|
285
|
+
addressRegion ||
|
|
286
|
+
postalCode ||
|
|
287
|
+
commonName ? (
|
|
288
|
+
<Place
|
|
289
|
+
commonName={commonName}
|
|
187
290
|
streetAddress={streetAddress}
|
|
188
291
|
addressLocality={addressLocality}
|
|
189
292
|
addressRegion={addressRegion}
|
|
190
293
|
postalCode={postalCode}
|
|
191
|
-
|
|
294
|
+
/>
|
|
295
|
+
) : null}
|
|
192
296
|
|
|
297
|
+
{opening_time && closing_time ? (
|
|
298
|
+
<Season
|
|
193
299
|
season_start={season_start}
|
|
194
300
|
season_end={season_end}
|
|
195
|
-
|
|
301
|
+
opening_time={opening_time}
|
|
302
|
+
closing_time={closing_time}
|
|
303
|
+
name={name}
|
|
196
304
|
offSeasonDetails={offSeasonDetails}
|
|
197
|
-
|
|
198
305
|
/>
|
|
199
|
-
|
|
200
|
-
|
|
306
|
+
) : (
|
|
307
|
+
<div className="react-markdown">
|
|
308
|
+
<Markdown>{description.data.description}</Markdown>
|
|
309
|
+
</div>
|
|
310
|
+
)}
|
|
311
|
+
</div>
|
|
312
|
+
</>
|
|
313
|
+
);
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
export const PaddleLocationCard = ({
|
|
317
|
+
svg,
|
|
318
|
+
name,
|
|
319
|
+
link,
|
|
320
|
+
address,
|
|
321
|
+
description,
|
|
322
|
+
opening_time,
|
|
323
|
+
closing_time,
|
|
324
|
+
streetAddress,
|
|
325
|
+
addressLocality,
|
|
326
|
+
addressRegion,
|
|
327
|
+
postalCode,
|
|
328
|
+
commonName,
|
|
329
|
+
season_start,
|
|
330
|
+
season_end,
|
|
331
|
+
phone,
|
|
332
|
+
offSeasonDetails,
|
|
333
|
+
}: PaddleLocationCardTypes) => {
|
|
334
|
+
const phoneNumber = Number(phone);
|
|
335
|
+
|
|
336
|
+
if (phone) {
|
|
337
|
+
return (
|
|
338
|
+
<div className="location">
|
|
339
|
+
<PhoneContent
|
|
340
|
+
link={link}
|
|
341
|
+
svg={svg}
|
|
342
|
+
name={name}
|
|
343
|
+
address={address}
|
|
344
|
+
description={description}
|
|
345
|
+
opening_time={opening_time}
|
|
346
|
+
closing_time={closing_time}
|
|
347
|
+
streetAddress={streetAddress}
|
|
348
|
+
addressLocality={addressLocality}
|
|
349
|
+
addressRegion={addressRegion}
|
|
350
|
+
postalCode={postalCode}
|
|
351
|
+
commonName={commonName}
|
|
352
|
+
season_start={season_start}
|
|
353
|
+
season_end={season_end}
|
|
354
|
+
offSeasonDetails={offSeasonDetails}
|
|
355
|
+
phone={phoneNumber}
|
|
356
|
+
/>
|
|
201
357
|
</div>
|
|
202
|
-
)
|
|
358
|
+
);
|
|
203
359
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
360
|
+
|
|
361
|
+
if (link.includes("http")) {
|
|
362
|
+
return (
|
|
363
|
+
<a
|
|
364
|
+
href={link}
|
|
365
|
+
className="location"
|
|
366
|
+
target="_blank"
|
|
367
|
+
rel="noopener noreferrer"
|
|
368
|
+
title={name}
|
|
209
369
|
>
|
|
210
370
|
<Content
|
|
211
371
|
svg={svg}
|
|
@@ -214,21 +374,36 @@ export function PaddleLocationCard({ svg, name, link, address, description, open
|
|
|
214
374
|
description={description}
|
|
215
375
|
opening_time={opening_time}
|
|
216
376
|
closing_time={closing_time}
|
|
217
|
-
|
|
218
377
|
streetAddress={streetAddress}
|
|
219
378
|
addressLocality={addressLocality}
|
|
220
379
|
addressRegion={addressRegion}
|
|
221
380
|
postalCode={postalCode}
|
|
222
381
|
commonName={commonName}
|
|
223
|
-
|
|
224
382
|
season_start={season_start}
|
|
225
383
|
season_end={season_end}
|
|
226
|
-
|
|
227
384
|
offSeasonDetails={offSeasonDetails}
|
|
228
|
-
|
|
229
385
|
/>
|
|
230
|
-
</
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
386
|
+
</a>
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
return (
|
|
390
|
+
<Link to={link} className="location">
|
|
391
|
+
<Content
|
|
392
|
+
svg={svg}
|
|
393
|
+
name={name}
|
|
394
|
+
address={address}
|
|
395
|
+
description={description}
|
|
396
|
+
opening_time={opening_time}
|
|
397
|
+
closing_time={closing_time}
|
|
398
|
+
streetAddress={streetAddress}
|
|
399
|
+
addressLocality={addressLocality}
|
|
400
|
+
addressRegion={addressRegion}
|
|
401
|
+
postalCode={postalCode}
|
|
402
|
+
commonName={commonName}
|
|
403
|
+
season_start={season_start}
|
|
404
|
+
season_end={season_end}
|
|
405
|
+
offSeasonDetails={offSeasonDetails}
|
|
406
|
+
/>
|
|
407
|
+
</Link>
|
|
408
|
+
);
|
|
409
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as React from "react"
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
import { PaddleLocationCard } from "./PaddleLocationCard";
|
|
3
3
|
import type { PaddleLocationCardTypes } from "./types/location-card-types";
|
|
4
4
|
|
|
@@ -9,8 +9,13 @@ interface LocationDeckTypes {
|
|
|
9
9
|
phone?: string;
|
|
10
10
|
nodes: PaddleLocationCardTypes[];
|
|
11
11
|
}
|
|
12
|
-
export
|
|
13
|
-
|
|
12
|
+
export const PaddleLocationDeck = ({
|
|
13
|
+
nodes,
|
|
14
|
+
season_start,
|
|
15
|
+
season_end,
|
|
16
|
+
phone,
|
|
17
|
+
background,
|
|
18
|
+
}: LocationDeckTypes) => {
|
|
14
19
|
return (
|
|
15
20
|
<section className="location-deck">
|
|
16
21
|
{nodes.map((location: PaddleLocationCardTypes) => (
|
|
@@ -24,5 +29,5 @@ export function PaddleLocationDeck({ nodes, season_start, season_end, phone, bac
|
|
|
24
29
|
/>
|
|
25
30
|
))}
|
|
26
31
|
</section>
|
|
27
|
-
)
|
|
28
|
-
}
|
|
32
|
+
);
|
|
33
|
+
};
|
package/src/PaddleSEO.tsx
CHANGED
|
@@ -7,10 +7,10 @@ interface BreadcrumbsTypes {
|
|
|
7
7
|
name?: string;
|
|
8
8
|
item?: string;
|
|
9
9
|
};
|
|
10
|
-
}
|
|
10
|
+
}
|
|
11
|
+
[];
|
|
11
12
|
// I could probably pass it two arguments instead but for now
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
const Breadcrumbs = (breadcrumbs: BreadcrumbsTypes) => {
|
|
14
14
|
// remove the breadcrumbs.url from the Object.entries
|
|
15
15
|
// console.log(breadcrumbs.url);
|
|
16
16
|
const { url, ...rest } = breadcrumbs;
|
|
@@ -19,7 +19,6 @@ function Breadcrumbs(breadcrumbs: BreadcrumbsTypes) {
|
|
|
19
19
|
return null;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
22
|
return (
|
|
24
23
|
<Script type="application/ld+json">
|
|
25
24
|
{`
|
|
@@ -28,19 +27,19 @@ function Breadcrumbs(breadcrumbs: BreadcrumbsTypes) {
|
|
|
28
27
|
"@type": "BreadcrumbList",
|
|
29
28
|
"itemListElement": [
|
|
30
29
|
${Object.entries(rest).map(([key, breadcrumb]) => {
|
|
31
|
-
|
|
30
|
+
return `{
|
|
32
31
|
"@type": "ListItem",
|
|
33
32
|
"position": ${Number.parseInt(key) + 1},
|
|
34
33
|
"name": "${breadcrumb.name}",
|
|
35
34
|
"item": "${url}/${breadcrumb.item}"
|
|
36
|
-
}
|
|
37
|
-
|
|
35
|
+
}`;
|
|
36
|
+
})}
|
|
38
37
|
]
|
|
39
38
|
}
|
|
40
39
|
`}
|
|
41
40
|
</Script>
|
|
42
41
|
);
|
|
43
|
-
}
|
|
42
|
+
};
|
|
44
43
|
|
|
45
44
|
type SEOtypes = {
|
|
46
45
|
title?: string;
|
|
@@ -96,13 +95,24 @@ type SEOtypes = {
|
|
|
96
95
|
};
|
|
97
96
|
|
|
98
97
|
children: React.ReactNode;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export const PaddleSEO = ({ title, description, ogImage, ogImageDescription, breadcrumbs, strapiLocale, strapiLocation, allStrapiLocation, children }: SEOtypes) => {
|
|
98
|
+
};
|
|
102
99
|
|
|
100
|
+
export const PaddleSEO = ({
|
|
101
|
+
title,
|
|
102
|
+
description,
|
|
103
|
+
ogImage,
|
|
104
|
+
ogImageDescription,
|
|
105
|
+
breadcrumbs,
|
|
106
|
+
strapiLocale,
|
|
107
|
+
strapiLocation,
|
|
108
|
+
allStrapiLocation,
|
|
109
|
+
children,
|
|
110
|
+
}: SEOtypes) => {
|
|
103
111
|
const businessName = `${strapiLocale.name} Kayak & Paddleboard rentals and tours`;
|
|
104
112
|
|
|
105
|
-
const PaddleTitle = title
|
|
113
|
+
const PaddleTitle = title
|
|
114
|
+
? `${title} | ${businessName}`
|
|
115
|
+
: `${businessName} | ${strapiLocale.topbar.data.topbar} `;
|
|
106
116
|
// TODO: tagline would be a better fallback description
|
|
107
117
|
const PaddleDescription = description || strapiLocale.slogan;
|
|
108
118
|
// url: `${strapiLocale.url}${SE0.url}` || strapiLocale.url,
|
|
@@ -116,8 +126,13 @@ export const PaddleSEO = ({ title, description, ogImage, ogImageDescription, bre
|
|
|
116
126
|
// TODO: this is now allStrapiLocation.nodes
|
|
117
127
|
// TODO: I think this will be a keylocation piece
|
|
118
128
|
// console.log(strapiLocale.paymentAccepted);
|
|
119
|
-
const paymentAcceptedQuery = strapiLocale.paymentAccepted
|
|
120
|
-
|
|
129
|
+
const paymentAcceptedQuery = strapiLocale.paymentAccepted
|
|
130
|
+
? strapiLocale.paymentAccepted
|
|
131
|
+
: "";
|
|
132
|
+
const paymentAcceptedFormatted = paymentAcceptedQuery
|
|
133
|
+
.split("\n")
|
|
134
|
+
.map((payment: string) => payment.trim().replace("- ", ""))
|
|
135
|
+
.join(", ");
|
|
121
136
|
// console.log(paymentAcceptedFormatted);
|
|
122
137
|
|
|
123
138
|
// console.log(breadcrumbs);
|
|
@@ -152,10 +167,12 @@ export const PaddleSEO = ({ title, description, ogImage, ogImageDescription, bre
|
|
|
152
167
|
"postalCode": "${strapiLocation?.postalCode}",
|
|
153
168
|
"addressCountry": "US"
|
|
154
169
|
},
|
|
155
|
-
${
|
|
170
|
+
${
|
|
171
|
+
allStrapiLocation
|
|
172
|
+
? `
|
|
156
173
|
"department": [
|
|
157
174
|
${allStrapiLocation.nodes.map((location) => {
|
|
158
|
-
|
|
175
|
+
return `{
|
|
159
176
|
"name": "${location.name}",
|
|
160
177
|
"@type": "${location.schemaType}",
|
|
161
178
|
"address": {
|
|
@@ -166,10 +183,12 @@ export const PaddleSEO = ({ title, description, ogImage, ogImageDescription, bre
|
|
|
166
183
|
"postalCode": "${location.postalCode}",
|
|
167
184
|
"addressCountry": "US"
|
|
168
185
|
}
|
|
169
|
-
}
|
|
170
|
-
|
|
186
|
+
}`;
|
|
187
|
+
})}
|
|
171
188
|
],
|
|
172
|
-
`
|
|
189
|
+
`
|
|
190
|
+
: ""
|
|
191
|
+
}
|
|
173
192
|
"areaServed": {
|
|
174
193
|
"@type": "GeoCircle",
|
|
175
194
|
"geoMidpoint": {
|
|
@@ -189,10 +208,7 @@ export const PaddleSEO = ({ title, description, ogImage, ogImageDescription, bre
|
|
|
189
208
|
`}
|
|
190
209
|
</Script>
|
|
191
210
|
|
|
192
|
-
<Breadcrumbs
|
|
193
|
-
url={strapiLocale.url}
|
|
194
|
-
{...breadcrumbs}
|
|
195
|
-
/>
|
|
211
|
+
<Breadcrumbs url={strapiLocale.url} {...breadcrumbs} />
|
|
196
212
|
{children}
|
|
197
213
|
</>
|
|
198
214
|
);
|
|
@@ -217,4 +233,4 @@ return `{
|
|
|
217
233
|
"closes": "${location.closing_time}"
|
|
218
234
|
}`
|
|
219
235
|
})}
|
|
220
|
-
], */
|
|
236
|
+
], */
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { TestimonialTypes } from "./types/testimonial-types"
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { TestimonialTypes } from "./types/testimonial-types";
|
|
3
3
|
|
|
4
|
-
export
|
|
4
|
+
export const PaddleTestimonial = ({
|
|
5
|
+
id,
|
|
6
|
+
testimonial,
|
|
7
|
+
customer,
|
|
8
|
+
sign,
|
|
9
|
+
location,
|
|
10
|
+
}: TestimonialTypes) => {
|
|
5
11
|
return (
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
<li key={id}>
|
|
13
|
+
<p className="elbrus">
|
|
14
|
+
<span className="denali font-serif">“</span>
|
|
15
|
+
{testimonial}
|
|
16
|
+
<span className="denali font-serif">”</span>
|
|
17
|
+
</p>
|
|
18
|
+
<p>
|
|
19
|
+
{sign} {customer}
|
|
20
|
+
</p>
|
|
21
|
+
<p className="kosciuszko">{location}</p>
|
|
22
|
+
</li>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { PaddleTestimonial } from "./PaddleTestimonial"
|
|
3
|
-
import { type TestimonialTypes } from "./types/testimonial-types"
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { PaddleTestimonial } from "./PaddleTestimonial";
|
|
3
|
+
import { type TestimonialTypes } from "./types/testimonial-types";
|
|
4
4
|
|
|
5
5
|
interface TestimonialsTypes {
|
|
6
6
|
nodes: TestimonialTypes[];
|
|
7
7
|
}
|
|
8
|
-
export
|
|
8
|
+
export const PaddleTestimonials = ({ nodes }: TestimonialsTypes) => {
|
|
9
9
|
return (
|
|
10
|
-
<ul className=
|
|
10
|
+
<ul className="testimonials condor">
|
|
11
11
|
{nodes.map((testimonial) => (
|
|
12
12
|
<PaddleTestimonial key={testimonial.id} {...testimonial} />
|
|
13
13
|
))}
|
|
14
14
|
</ul>
|
|
15
|
-
)
|
|
16
|
-
}
|
|
15
|
+
);
|
|
16
|
+
};
|
package/src/PaddleTicket.tsx
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { Link } from "gatsby"
|
|
3
|
-
import { GatsbyImage } from "gatsby-plugin-image"
|
|
4
|
-
import type { PaddleTicketTypes } from "./types/ticket-types"
|
|
5
|
-
import { PaddleTime } from "./PaddleTime"
|
|
6
|
-
import { PaddleBookNow } from "./PaddleBookNow"
|
|
7
|
-
|
|
8
|
-
export function PaddleTicket({ ogimage, slug, name, start, finish, duration, timeframe, fitness, excerpt, price, peek, peek_tours_fall_back, tour_page, allStrapiSunsetTourTime, strapiLocaleName }: PaddleTicketTypes) {
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Link } from "gatsby";
|
|
3
|
+
import { GatsbyImage } from "gatsby-plugin-image";
|
|
4
|
+
import type { PaddleTicketTypes } from "./types/ticket-types";
|
|
5
|
+
import { PaddleTime } from "./PaddleTime";
|
|
6
|
+
import { PaddleBookNow } from "./PaddleBookNow";
|
|
9
7
|
|
|
8
|
+
export const PaddleTicket = ({
|
|
9
|
+
ogimage,
|
|
10
|
+
slug,
|
|
11
|
+
name,
|
|
12
|
+
start,
|
|
13
|
+
finish,
|
|
14
|
+
duration,
|
|
15
|
+
timeframe,
|
|
16
|
+
fitness,
|
|
17
|
+
excerpt,
|
|
18
|
+
price,
|
|
19
|
+
peek,
|
|
20
|
+
peek_tours_fall_back,
|
|
21
|
+
tour_page,
|
|
22
|
+
allStrapiSunsetTourTime,
|
|
23
|
+
strapiLocaleName,
|
|
24
|
+
}: PaddleTicketTypes) => {
|
|
10
25
|
const time = PaddleTime({
|
|
11
26
|
start: start,
|
|
12
27
|
finish: finish,
|
|
@@ -14,7 +29,7 @@ export function PaddleTicket({ ogimage, slug, name, start, finish, duration, tim
|
|
|
14
29
|
timeframe: timeframe,
|
|
15
30
|
allStrapiSunsetTourTime: allStrapiSunsetTourTime,
|
|
16
31
|
allStrapiMoonlightTourDateTime: { nodes: [] }, // Provide an empty nodes array or the correct data as needed
|
|
17
|
-
slug: slug
|
|
32
|
+
slug: slug,
|
|
18
33
|
});
|
|
19
34
|
|
|
20
35
|
return (
|
|
@@ -27,19 +42,17 @@ export function PaddleTicket({ ogimage, slug, name, start, finish, duration, tim
|
|
|
27
42
|
className="card__image"
|
|
28
43
|
/>
|
|
29
44
|
</Link>
|
|
30
|
-
<div className=
|
|
45
|
+
<div className="ticket__header">
|
|
31
46
|
<h4 className="card__title">
|
|
32
|
-
<Link to={`/${tour_page}/${slug}`}>
|
|
33
|
-
{name}
|
|
34
|
-
</Link>
|
|
47
|
+
<Link to={`/${tour_page}/${slug}`}>{name}</Link>
|
|
35
48
|
</h4>
|
|
36
|
-
|
|
37
|
-
<div className=
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
|
|
50
|
+
<div className="ticket__money">
|
|
51
|
+
<h5>${price}</h5>
|
|
52
|
+
<PaddleBookNow
|
|
53
|
+
peek_base={peek || peek_tours_fall_back}
|
|
54
|
+
strapiLocaleName={strapiLocaleName}
|
|
55
|
+
/>
|
|
43
56
|
</div>
|
|
44
57
|
</div>
|
|
45
58
|
|
|
@@ -47,15 +60,18 @@ export function PaddleTicket({ ogimage, slug, name, start, finish, duration, tim
|
|
|
47
60
|
{/* // TODO: heavy handed but once the backup is there we can work on this */}
|
|
48
61
|
{/* // TODO: I'd like a spec backup here */}
|
|
49
62
|
|
|
50
|
-
{slug !==
|
|
63
|
+
{slug !== "2hour" && slug !== "3hour" ? (
|
|
51
64
|
<>
|
|
52
65
|
<h4>{time.entry}</h4>
|
|
53
|
-
{fitness ?
|
|
66
|
+
{fitness ? (
|
|
67
|
+
<h4 className="capitalize">
|
|
68
|
+
{fitness} <span>Fitness</span>
|
|
69
|
+
</h4>
|
|
70
|
+
) : null}
|
|
54
71
|
</>
|
|
55
|
-
) : null
|
|
56
|
-
|
|
72
|
+
) : null}
|
|
73
|
+
<p>{excerpt}</p>
|
|
57
74
|
</div>
|
|
58
|
-
|
|
59
75
|
</section>
|
|
60
|
-
)
|
|
61
|
-
}
|
|
76
|
+
);
|
|
77
|
+
};
|
package/src/phone.tsx
CHANGED
|
@@ -1,33 +1,28 @@
|
|
|
1
|
-
import * as React from "react"
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
|
|
3
3
|
interface FormatPhoneNumberTypes {
|
|
4
4
|
phoneNumberString: number;
|
|
5
5
|
}
|
|
6
|
-
|
|
6
|
+
const FormatPhoneNumber = ({ phoneNumberString }: FormatPhoneNumberTypes) => {
|
|
7
7
|
const phoneNumber = String(phoneNumberString);
|
|
8
|
-
const cleaned = `${phoneNumber}`.replace(/\D/g,
|
|
8
|
+
const cleaned = `${phoneNumber}`.replace(/\D/g, "");
|
|
9
9
|
const match = cleaned.match(/^(\d{3})(\d{3})(\d{4})$/);
|
|
10
10
|
if (match) {
|
|
11
11
|
return `(${match[1]}) ${match[2]}-${match[3]}`;
|
|
12
12
|
}
|
|
13
13
|
return null;
|
|
14
|
-
}
|
|
14
|
+
};
|
|
15
15
|
|
|
16
16
|
type PhoneTypes = {
|
|
17
17
|
phone: number;
|
|
18
|
-
}
|
|
18
|
+
};
|
|
19
19
|
|
|
20
20
|
const Phone = ({ phone }: PhoneTypes) => {
|
|
21
|
-
|
|
22
21
|
return (
|
|
23
|
-
<a
|
|
24
|
-
href={`tel:${phone}`}
|
|
25
|
-
rel="norel norefferer"
|
|
26
|
-
className="button"
|
|
27
|
-
>
|
|
22
|
+
<a href={`tel:${phone}`} rel="norel norefferer" className="button">
|
|
28
23
|
Phone: <FormatPhoneNumber phoneNumberString={phone} />
|
|
29
24
|
</a>
|
|
30
|
-
)
|
|
31
|
-
}
|
|
25
|
+
);
|
|
26
|
+
};
|
|
32
27
|
|
|
33
|
-
export default Phone
|
|
28
|
+
export default Phone;
|