@ticketboothapp/booking 0.1.18 → 0.1.20

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.
Files changed (152) hide show
  1. package/package.json +1 -1
  2. package/src/components/BookingWidget.tsx +282 -26
  3. package/src/components/ManageBookingView.tsx +75 -23
  4. package/src/components/booking/BookingProductGrid.tsx +1 -1
  5. package/src/components/booking/Calendar.module.css +3 -3
  6. package/src/components/booking/CheckoutForm.tsx +1 -1
  7. package/src/components/booking/PickupLocationSelector.tsx +1 -1
  8. package/src/index.ts +3 -1
  9. package/src/app/photo-sessions/photo-packages.ts +0 -75
  10. package/src/assets/icons/minus.svg +0 -7
  11. package/src/assets/icons/partner-logos/getyourguide.svg +0 -8
  12. package/src/assets/icons/plus.svg +0 -3
  13. package/src/colours.css +0 -23
  14. package/src/components/BookingDetails.module.css +0 -1591
  15. package/src/components/BookingDetails.tsx +0 -2264
  16. package/src/components/JobApplicationDialog.module.css +0 -440
  17. package/src/components/JobApplicationDialog.tsx +0 -620
  18. package/src/components/PhoneInputWithCountry.module.css +0 -131
  19. package/src/components/PhoneInputWithCountry.tsx +0 -44
  20. package/src/components/PickupLocationDialog.module.css +0 -360
  21. package/src/components/PickupLocationDialog.tsx +0 -357
  22. package/src/components/PickupLocationMap.tsx +0 -110
  23. package/src/components/PostBookingDependentAddOnUpsell.module.css +0 -174
  24. package/src/components/PostBookingDependentAddOnUpsell.tsx +0 -407
  25. package/src/components/accordion.css +0 -27
  26. package/src/components/accordion.tsx +0 -29
  27. package/src/components/analytics/AnalyticsConsentRestore.tsx +0 -19
  28. package/src/components/analytics/AnalyticsScripts.tsx +0 -106
  29. package/src/components/analytics/CookieConsentBanner.css +0 -86
  30. package/src/components/analytics/CookieConsentBanner.tsx +0 -102
  31. package/src/components/bottom-sheet.module.css +0 -78
  32. package/src/components/bottom-sheet.tsx +0 -60
  33. package/src/components/breadcrumb.module.css +0 -40
  34. package/src/components/breadcrumb.tsx +0 -36
  35. package/src/components/button.css +0 -245
  36. package/src/components/button.tsx +0 -152
  37. package/src/components/client-bottom-sheet.tsx +0 -14
  38. package/src/components/colorable-svg.tsx +0 -29
  39. package/src/components/conditional-footer.tsx +0 -27
  40. package/src/components/contact-us.module.css +0 -147
  41. package/src/components/contact-us.tsx +0 -49
  42. package/src/components/email-signup.css +0 -151
  43. package/src/components/email-signup.tsx +0 -63
  44. package/src/components/faq-wrapper.module.css +0 -47
  45. package/src/components/faq-wrapper.tsx +0 -15
  46. package/src/components/footer.css +0 -187
  47. package/src/components/footer.tsx +0 -143
  48. package/src/components/global-simple-modal.tsx +0 -33
  49. package/src/components/google-review-summary.module.css +0 -77
  50. package/src/components/google-review-summary.tsx +0 -50
  51. package/src/components/hero-image.css +0 -13
  52. package/src/components/hero-image.tsx +0 -44
  53. package/src/components/image.css +0 -29
  54. package/src/components/image.tsx +0 -113
  55. package/src/components/language-aware-link.tsx +0 -72
  56. package/src/components/language-switcher.module.css +0 -124
  57. package/src/components/language-switcher.tsx +0 -75
  58. package/src/components/map-section.css +0 -59
  59. package/src/components/map-section.tsx +0 -63
  60. package/src/components/navbar.module.css +0 -152
  61. package/src/components/navbar.tsx +0 -125
  62. package/src/components/parallax-provider.tsx +0 -11
  63. package/src/components/product-tag.module.css +0 -30
  64. package/src/components/product-tag.tsx +0 -34
  65. package/src/components/product-theme-pages/best-option.module.css +0 -70
  66. package/src/components/product-theme-pages/best-option.tsx +0 -35
  67. package/src/components/product-theme-pages/extended-tour-options.module.css +0 -22
  68. package/src/components/product-theme-pages/extended-tour-options.tsx +0 -11
  69. package/src/components/product-theme-pages/image-modal.tsx +0 -248
  70. package/src/components/product-theme-pages/photo-gallery.module.css +0 -200
  71. package/src/components/product-theme-pages/photo-gallery.tsx +0 -90
  72. package/src/components/product-theme-pages/product-theme-page-layout.module.css +0 -13
  73. package/src/components/product-theme-pages/product-theme-page-layout.tsx +0 -67
  74. package/src/components/product-theme-pages/top-of-fold.module.css +0 -179
  75. package/src/components/product-theme-pages/top-of-fold.tsx +0 -80
  76. package/src/components/product-tile/image-only-product-tile-desktop.module.css +0 -106
  77. package/src/components/product-tile/image-only-product-tile-desktop.tsx +0 -56
  78. package/src/components/product-tile/image-only-product-tile-mobile.module.css +0 -122
  79. package/src/components/product-tile/image-only-product-tile-mobile.tsx +0 -89
  80. package/src/components/product-tile/image-only-product-tile.tsx +0 -44
  81. package/src/components/product-tile/product-tile-card.module.css +0 -84
  82. package/src/components/product-tile/product-tile-card.tsx +0 -61
  83. package/src/components/review-highlights-section.css +0 -85
  84. package/src/components/review-highlights-section.tsx +0 -127
  85. package/src/components/season-closure-overlay.module.css +0 -99
  86. package/src/components/season-closure-overlay.tsx +0 -98
  87. package/src/components/simple-modal.tsx +0 -69
  88. package/src/components/simple-top-of-fold.module.css +0 -76
  89. package/src/components/simple-top-of-fold.tsx +0 -34
  90. package/src/components/spacer.css +0 -41
  91. package/src/components/spacer.tsx +0 -23
  92. package/src/components/star-rating.module.css +0 -74
  93. package/src/components/star-rating.tsx +0 -48
  94. package/src/components/terms/TermsContent.tsx +0 -178
  95. package/src/components/title-subtitle.module.css +0 -10
  96. package/src/components/title-subtitle.tsx +0 -30
  97. package/src/components/translatable-reviews.tsx +0 -75
  98. package/src/components/value-pill.module.css +0 -59
  99. package/src/components/value-pill.tsx +0 -46
  100. package/src/components/value-props.css +0 -185
  101. package/src/components/value-props.tsx +0 -88
  102. package/src/constants/booking-guide-quiz.ts +0 -64
  103. package/src/constants/contact-info.ts +0 -2
  104. package/src/constants/faq.ts +0 -44
  105. package/src/constants/images.ts +0 -556
  106. package/src/constants/json-ld/faq-json-ld.tsx +0 -170
  107. package/src/constants/json-ld/homepage-json-ld.tsx +0 -138
  108. package/src/constants/json-ld/job-posting-json-ld.tsx +0 -92
  109. package/src/constants/json-ld/organization-json-ld.tsx +0 -62
  110. package/src/constants/json-ld/page-json-ld.tsx +0 -6
  111. package/src/constants/json-ld/product-json-ld.tsx +0 -154
  112. package/src/constants/json-ld/review-json-ld.tsx +0 -377
  113. package/src/constants/navigation-links/footer-links.ts +0 -48
  114. package/src/constants/navigation-links/nav-bar-links.ts +0 -41
  115. package/src/constants/navigation-links/navigation-link.ts +0 -6
  116. package/src/constants/pill-values.ts +0 -210
  117. package/src/constants/products.ts +0 -155
  118. package/src/constants/quiz-recommendations.ts +0 -506
  119. package/src/constants/reviews.ts +0 -75
  120. package/src/constants/staff.ts +0 -197
  121. package/src/constants/value-props.ts +0 -58
  122. package/src/data/dap-descriptions/session-couples-families-friends.en.json +0 -61
  123. package/src/data/dap-descriptions/session-elopements.en.json +0 -60
  124. package/src/data/dap-descriptions/session-proposals.en.json +0 -60
  125. package/src/data/product-descriptions/afternoon-delight.en.json +0 -35
  126. package/src/data/product-descriptions/emerald-lake-escape.en.json +0 -68
  127. package/src/data/product-descriptions/lake-louise-adventure.en.json +0 -74
  128. package/src/data/product-descriptions/moraine-lake-adventure.en.json +0 -78
  129. package/src/data/product-descriptions/moraine-lake-sunrise-lake-louise-golden-hour.en.json +0 -65
  130. package/src/data/product-descriptions/moraine-lake-sunrise.en.json +0 -64
  131. package/src/data/product-descriptions/private-tour.en.json +0 -80
  132. package/src/data/product-descriptions/two-lakes-combo.en.json +0 -65
  133. package/src/data/products-config.json +0 -101
  134. package/src/hooks/use-bottom-sheet.tsx +0 -15
  135. package/src/hooks/use-simple-modal.tsx +0 -27
  136. package/src/hooks/useBookingSourceMetadataFromLocation.ts +0 -21
  137. package/src/hooks/useEmailSubscription.tsx +0 -103
  138. package/src/hooks/useEmbeddedInIframe.ts +0 -16
  139. package/src/hooks/useIsBookingLaunchLive.ts +0 -49
  140. package/src/hooks/useQuiz.tsx +0 -210
  141. package/src/providers/bottom-sheet-provider.tsx +0 -40
  142. package/src/providers/dependent-add-on-dialog-provider.tsx +0 -105
  143. package/src/radius.css +0 -5
  144. package/src/spacing.css +0 -7
  145. package/src/strings/en.json +0 -1774
  146. package/src/strings/es.json +0 -1573
  147. package/src/strings/fr.json +0 -1573
  148. package/src/strings/index.js +0 -23
  149. package/src/text-style.css +0 -97
  150. package/src/types/fareharbor.d.ts +0 -12
  151. package/src/types/quiz.ts +0 -59
  152. package/src/utils/currency-converter.ts +0 -101
@@ -1,620 +0,0 @@
1
- 'use client';
2
-
3
- import React, { useState, useEffect } from 'react';
4
- import {
5
- getPresignedUploadUrl,
6
- uploadFileToPresignedUrl,
7
- submitJobApplication,
8
- type SubmitApplicationPayload,
9
- } from '@/lib/job-application-api';
10
- import strings from '@/strings';
11
- import PhoneInputWithCountry from '@/components/PhoneInputWithCountry';
12
- import styles from './JobApplicationDialog.module.css';
13
- import Button, { ButtonHoverColor } from './button';
14
-
15
- const JOB_ID_GUEST_EXPERIENCE = 'guest-experience-coordinator';
16
-
17
- function YesNoField({
18
- id,
19
- label,
20
- value,
21
- onChange,
22
- t,
23
- submitting,
24
- required,
25
- }: {
26
- id: string;
27
- label: string;
28
- value: string;
29
- onChange: (v: string) => void;
30
- t: (key: string) => string;
31
- submitting: boolean;
32
- required?: boolean;
33
- }) {
34
- return (
35
- <div className={styles.formGroup}>
36
- <label className={styles.label}>
37
- {label} {required && '*'}
38
- </label>
39
- <div className={styles.radioGroup}>
40
- <label className={styles.radioLabel}>
41
- <input
42
- type="radio"
43
- name={id}
44
- value="YES"
45
- checked={value === 'YES'}
46
- onChange={(e) => onChange(e.target.value)}
47
- disabled={submitting}
48
- required={required}
49
- />
50
- <span>{t('yes')}</span>
51
- </label>
52
- <label className={styles.radioLabel}>
53
- <input
54
- type="radio"
55
- name={id}
56
- value="NO"
57
- checked={value === 'NO'}
58
- onChange={(e) => onChange(e.target.value)}
59
- disabled={submitting}
60
- />
61
- <span>{t('no')}</span>
62
- </label>
63
- </div>
64
- </div>
65
- );
66
- }
67
-
68
- interface JobApplicationDialogProps {
69
- isOpen: boolean;
70
- onClose: () => void;
71
- jobId: string;
72
- jobTitle: string;
73
- jobDescription: string;
74
- jobDescriptionExpanded?: string;
75
- }
76
-
77
- export default function JobApplicationDialog({
78
- isOpen,
79
- onClose,
80
- jobId,
81
- jobTitle,
82
- jobDescription,
83
- jobDescriptionExpanded,
84
- }: JobApplicationDialogProps) {
85
- const jobAppStrings = (strings as { careers?: { jobApplication?: Record<string, string> } }).careers?.jobApplication;
86
- const t = (key: string) => jobAppStrings?.[key] ?? key;
87
-
88
- const [name, setName] = useState('');
89
- const [email, setEmail] = useState('');
90
- const [phone, setPhone] = useState('');
91
- const [eligibleToWorkInCanada, setEligibleToWorkInCanada] = useState<string>('');
92
- const [accommodationInBowValley, setAccommodationInBowValley] = useState<string>('');
93
- const [whyJoinViaVia, setWhyJoinViaVia] = useState('');
94
- const [comfortableEarlyMornings, setComfortableEarlyMornings] = useState<string>('');
95
- const [languagesSpoken, setLanguagesSpoken] = useState('');
96
- const [fastPacedExperience, setFastPacedExperience] = useState<string>('');
97
- const [whatMakesYouReliable, setWhatMakesYouReliable] = useState('');
98
- const [eligibleToWorkInCanadaExplain, setEligibleToWorkInCanadaExplain] = useState('');
99
- const [accommodationInBowValleyExplain, setAccommodationInBowValleyExplain] = useState('');
100
- const [fastPacedExperienceExplain, setFastPacedExperienceExplain] = useState('');
101
- const [resumeFile, setResumeFile] = useState<File | null>(null);
102
- const [coverLetterFile, setCoverLetterFile] = useState<File | null>(null);
103
- const [descriptionExpanded, setDescriptionExpanded] = useState(false);
104
- const [error, setError] = useState<string | null>(null);
105
-
106
- useEffect(() => {
107
- if (isOpen) setDescriptionExpanded(false);
108
- }, [isOpen]);
109
- const [success, setSuccess] = useState(false);
110
- const [submitting, setSubmitting] = useState(false);
111
- const [showCloseConfirm, setShowCloseConfirm] = useState(false);
112
-
113
- const hasMeaningfulPhone = phone.replace(/\D/g, '').length > 1;
114
- const isFormDirty = Boolean(
115
- name.trim() ||
116
- email.trim() ||
117
- hasMeaningfulPhone ||
118
- eligibleToWorkInCanada ||
119
- accommodationInBowValley ||
120
- whyJoinViaVia.trim() ||
121
- comfortableEarlyMornings ||
122
- languagesSpoken.trim() ||
123
- fastPacedExperience ||
124
- whatMakesYouReliable.trim() ||
125
- eligibleToWorkInCanadaExplain.trim() ||
126
- accommodationInBowValleyExplain.trim() ||
127
- fastPacedExperienceExplain.trim() ||
128
- resumeFile ||
129
- coverLetterFile
130
- );
131
-
132
- const resetForm = () => {
133
- setName('');
134
- setEmail('');
135
- setPhone('');
136
- setEligibleToWorkInCanada('');
137
- setAccommodationInBowValley('');
138
- setWhyJoinViaVia('');
139
- setComfortableEarlyMornings('');
140
- setLanguagesSpoken('');
141
- setFastPacedExperience('');
142
- setWhatMakesYouReliable('');
143
- setEligibleToWorkInCanadaExplain('');
144
- setAccommodationInBowValleyExplain('');
145
- setFastPacedExperienceExplain('');
146
- setResumeFile(null);
147
- setCoverLetterFile(null);
148
- setError(null);
149
- setSuccess(false);
150
- setShowCloseConfirm(false);
151
- };
152
-
153
- const handleClose = () => {
154
- setShowCloseConfirm(false);
155
- resetForm();
156
- onClose();
157
- };
158
-
159
- const requestClose = () => {
160
- if (!success && isFormDirty) {
161
- setShowCloseConfirm(true);
162
- } else {
163
- handleClose();
164
- }
165
- };
166
-
167
- const handleSubmit = async (e: React.FormEvent) => {
168
- e.preventDefault();
169
- setError(null);
170
-
171
- if (!name.trim()) {
172
- setError(t('name') + ' is required');
173
- return;
174
- }
175
- if (!email.trim()) {
176
- setError(t('email') + ' is required');
177
- return;
178
- }
179
- if (!email.includes('@')) {
180
- setError('Please enter a valid email address');
181
- return;
182
- }
183
- if (!eligibleToWorkInCanada) {
184
- setError(t('eligibleToWorkInCanada') + ' is required');
185
- return;
186
- }
187
- if (eligibleToWorkInCanada === 'NO' && !eligibleToWorkInCanadaExplain.trim()) {
188
- setError(t('followUpRequired'));
189
- return;
190
- }
191
- if (!accommodationInBowValley) {
192
- setError(t('accommodationInBowValley') + ' is required');
193
- return;
194
- }
195
- if (accommodationInBowValley === 'NO' && !accommodationInBowValleyExplain.trim()) {
196
- setError(t('followUpRequired'));
197
- return;
198
- }
199
- if (!whyJoinViaVia.trim()) {
200
- setError(t('whyJoinViaVia') + ' is required');
201
- return;
202
- }
203
- if (!comfortableEarlyMornings) {
204
- setError(t('comfortableEarlyMornings') + ' is required');
205
- return;
206
- }
207
- if (!languagesSpoken.trim()) {
208
- setError(t('languagesSpoken') + ' is required');
209
- return;
210
- }
211
- if (!fastPacedExperience) {
212
- setError(t('fastPacedExperience') + ' is required');
213
- return;
214
- }
215
- if (!whatMakesYouReliable.trim()) {
216
- setError(t('whatMakesYouReliable') + ' is required');
217
- return;
218
- }
219
- if (!resumeFile) {
220
- setError(t('resume') + ' is required');
221
- return;
222
- }
223
-
224
- const allowedResumeTypes = ['.pdf', '.doc', '.docx'];
225
- const resumeExt = resumeFile.name.substring(resumeFile.name.lastIndexOf('.')).toLowerCase();
226
- if (!allowedResumeTypes.includes(resumeExt)) {
227
- setError('Resume must be PDF, DOC, or DOCX');
228
- return;
229
- }
230
-
231
- setSubmitting(true);
232
-
233
- try {
234
- // Upload resume
235
- const resumePresigned = await getPresignedUploadUrl(jobId, 'resume', resumeFile.name);
236
- await uploadFileToPresignedUrl(
237
- resumePresigned.uploadUrl,
238
- resumeFile,
239
- resumePresigned.contentType
240
- );
241
- const resumeS3Key = resumePresigned.s3Key;
242
-
243
- // Upload cover letter if provided
244
- let coverLetterS3Key: string | undefined;
245
- if (coverLetterFile) {
246
- const clPresigned = await getPresignedUploadUrl(jobId, 'coverLetter', coverLetterFile.name);
247
- await uploadFileToPresignedUrl(
248
- clPresigned.uploadUrl,
249
- coverLetterFile,
250
- clPresigned.contentType
251
- );
252
- coverLetterS3Key = clPresigned.s3Key;
253
- }
254
-
255
- const payload: SubmitApplicationPayload = {
256
- jobId,
257
- fullName: name.trim(),
258
- email: email.trim(),
259
- phone: hasMeaningfulPhone ? phone.trim() : undefined,
260
- answers: {
261
- eligibleToWorkInCanada: eligibleToWorkInCanada.trim(),
262
- eligibleToWorkInCanadaExplain: eligibleToWorkInCanadaExplain.trim(),
263
- accommodationInBowValley: accommodationInBowValley.trim(),
264
- accommodationInBowValleyExplain: accommodationInBowValleyExplain.trim(),
265
- whyJoinViaVia: whyJoinViaVia.trim(),
266
- comfortableEarlyMornings: comfortableEarlyMornings.trim(),
267
- languagesSpoken: languagesSpoken.trim(),
268
- fastPacedExperience: fastPacedExperience.trim(),
269
- fastPacedExperienceExplain: fastPacedExperienceExplain.trim(),
270
- whatMakesYouReliable: whatMakesYouReliable.trim(),
271
- },
272
- resumeS3Key,
273
- coverLetterS3Key,
274
- };
275
-
276
- await submitJobApplication(payload);
277
- setSuccess(true);
278
- } catch (err) {
279
- setError(err instanceof Error ? err.message : t('error'));
280
- } finally {
281
- setSubmitting(false);
282
- }
283
- };
284
-
285
- if (!isOpen) return null;
286
-
287
- const handleOverlayClick = () => {
288
- if (showCloseConfirm) {
289
- setShowCloseConfirm(false);
290
- } else {
291
- requestClose();
292
- }
293
- };
294
-
295
- return (
296
- <div
297
- className={styles.overlay}
298
- onClick={handleOverlayClick}
299
- role="dialog"
300
- aria-modal="true"
301
- aria-labelledby="job-application-dialog-title"
302
- >
303
- <div className={styles.modal} onClick={(e) => e.stopPropagation()}>
304
- <div className={`${styles.header} ${descriptionExpanded ? styles.headerExpanded : ''}`}>
305
- <div className={styles.headerContent}>
306
- <h2 id="job-application-dialog-title" className={styles.title}>
307
- {jobTitle}
308
- </h2>
309
- <div
310
- className={`${styles.descriptionSection} ${descriptionExpanded ? styles.descriptionExpanded : ''}`}
311
- >
312
- {descriptionExpanded && jobDescriptionExpanded ? (
313
- <div
314
- className={styles.descriptionExpandedContent}
315
- dangerouslySetInnerHTML={{ __html: jobDescriptionExpanded }}
316
- />
317
- ) : (
318
- <p className={styles.description}>{jobDescription}</p>
319
- )}
320
- <button
321
- type="button"
322
- onClick={() => setDescriptionExpanded((v) => !v)}
323
- className={styles.descriptionToggle}
324
- aria-label={descriptionExpanded ? t('collapseDescription') : t('expandDescription')}
325
- aria-expanded={descriptionExpanded}
326
- >
327
- <svg width="20" height="20" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24">
328
- <path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
329
- </svg>
330
- </button>
331
- </div>
332
- </div>
333
- <button
334
- type="button"
335
- onClick={requestClose}
336
- className={styles.closeBtn}
337
- aria-label={t('close')}
338
- >
339
- <svg width="24" height="24" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24">
340
- <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
341
- </svg>
342
- </button>
343
- </div>
344
-
345
- <div className={styles.formRow}>
346
- <div className={styles.bodyScroll}>
347
- <div className={styles.content}>
348
- {success ? (
349
- <>
350
- <div className={styles.success}>{t('success')}</div>
351
- <div className={styles.footer}>
352
- <button type="button" onClick={handleClose} className={styles.submitBtn}>
353
- {t('close')}
354
- </button>
355
- </div>
356
- </>
357
- ) : showCloseConfirm ? (
358
- <div className={styles.closeConfirm}>
359
- <p className={styles.closeConfirmTitle}>{t('closeConfirmTitle')}</p>
360
- <p className={styles.closeConfirmMessage}>{t('closeConfirmMessage')}</p>
361
- <div className={styles.closeConfirmActions}>
362
- <button
363
- type="button"
364
- onClick={() => setShowCloseConfirm(false)}
365
- className={styles.cancelBtn}
366
- >
367
- {t('keepEditing')}
368
- </button>
369
- <button
370
- type="button"
371
- onClick={handleClose}
372
- className={styles.submitBtn}
373
- >
374
- {t('discard')}
375
- </button>
376
- </div>
377
- </div>
378
- ) : (
379
- <form onSubmit={handleSubmit} className={styles.form}>
380
- <div className={styles.formGroup}>
381
- <label htmlFor="name" className={styles.label}>
382
- {t('name')} *
383
- </label>
384
- <input
385
- id="name"
386
- type="text"
387
- value={name}
388
- onChange={(e) => setName(e.target.value)}
389
- className={styles.input}
390
- required
391
- disabled={submitting}
392
- />
393
- </div>
394
-
395
- <div className={styles.formGroup}>
396
- <label htmlFor="email" className={styles.label}>
397
- {t('email')} *
398
- </label>
399
- <input
400
- id="email"
401
- type="email"
402
- value={email}
403
- onChange={(e) => setEmail(e.target.value)}
404
- className={styles.input}
405
- required
406
- disabled={submitting}
407
- />
408
- </div>
409
-
410
- <div className={styles.formGroup}>
411
- <label htmlFor="phone" className={styles.label}>
412
- {t('phoneNumber')}
413
- </label>
414
- <PhoneInputWithCountry
415
- id="phone"
416
- value={phone}
417
- onChange={(value) => setPhone(value ?? '')}
418
- placeholder="e.g. +1 403 555 0123"
419
- disabled={submitting}
420
- className={styles.phoneInputMatch}
421
- />
422
- </div>
423
-
424
- <YesNoField
425
- id="eligibleToWorkInCanada"
426
- label={t('eligibleToWorkInCanada')}
427
- value={eligibleToWorkInCanada}
428
- onChange={setEligibleToWorkInCanada}
429
- t={t}
430
- submitting={submitting}
431
- required
432
- />
433
- {eligibleToWorkInCanada === 'NO' && (
434
- <div className={styles.formGroup}>
435
- <label htmlFor="eligibleToWorkInCanadaExplain" className={styles.label}>
436
- {t('eligibleToWorkInCanadaFollowUp')} *
437
- </label>
438
- <input
439
- id="eligibleToWorkInCanadaExplain"
440
- type="text"
441
- value={eligibleToWorkInCanadaExplain}
442
- onChange={(e) => setEligibleToWorkInCanadaExplain(e.target.value)}
443
- className={styles.input}
444
- required={eligibleToWorkInCanada === 'NO'}
445
- disabled={submitting}
446
- />
447
- </div>
448
- )}
449
-
450
- <YesNoField
451
- id="accommodationInBowValley"
452
- label={t('accommodationInBowValley')}
453
- value={accommodationInBowValley}
454
- onChange={setAccommodationInBowValley}
455
- t={t}
456
- submitting={submitting}
457
- required
458
- />
459
- {accommodationInBowValley === 'NO' && (
460
- <div className={styles.formGroup}>
461
- <label htmlFor="accommodationInBowValleyExplain" className={styles.label}>
462
- {t('accommodationInBowValleyFollowUp')} *
463
- </label>
464
- <input
465
- id="accommodationInBowValleyExplain"
466
- type="text"
467
- value={accommodationInBowValleyExplain}
468
- onChange={(e) => setAccommodationInBowValleyExplain(e.target.value)}
469
- className={styles.input}
470
- required={accommodationInBowValley === 'NO'}
471
- disabled={submitting}
472
- />
473
- </div>
474
- )}
475
-
476
- <div className={styles.formGroup}>
477
- <label htmlFor="whyJoinViaVia" className={styles.label}>
478
- {t('whyJoinViaVia')} *
479
- </label>
480
- <textarea
481
- id="whyJoinViaVia"
482
- value={whyJoinViaVia}
483
- onChange={(e) => setWhyJoinViaVia(e.target.value)}
484
- className={`${styles.input} ${styles.textarea}`}
485
- disabled={submitting}
486
- required
487
- />
488
- </div>
489
-
490
- <YesNoField
491
- id="comfortableEarlyMornings"
492
- label={t('comfortableEarlyMornings')}
493
- value={comfortableEarlyMornings}
494
- onChange={setComfortableEarlyMornings}
495
- t={t}
496
- submitting={submitting}
497
- required
498
- />
499
-
500
- <div className={styles.formGroup}>
501
- <label htmlFor="languagesSpoken" className={styles.label}>
502
- {t('languagesSpoken')} *
503
- </label>
504
- <input
505
- id="languagesSpoken"
506
- type="text"
507
- value={languagesSpoken}
508
- onChange={(e) => setLanguagesSpoken(e.target.value)}
509
- className={styles.input}
510
- required
511
- disabled={submitting}
512
- />
513
- </div>
514
-
515
- <YesNoField
516
- id="fastPacedExperience"
517
- label={t('fastPacedExperience')}
518
- value={fastPacedExperience}
519
- onChange={setFastPacedExperience}
520
- t={t}
521
- submitting={submitting}
522
- required
523
- />
524
- {(fastPacedExperience === 'YES' || fastPacedExperience === 'NO') && (
525
- <div className={styles.formGroup}>
526
- <label htmlFor="fastPacedExperienceExplain" className={styles.label}>
527
- {t('explainOptional')}
528
- </label>
529
- <input
530
- id="fastPacedExperienceExplain"
531
- type="text"
532
- value={fastPacedExperienceExplain}
533
- onChange={(e) => setFastPacedExperienceExplain(e.target.value)}
534
- className={styles.input}
535
- disabled={submitting}
536
- />
537
- </div>
538
- )}
539
-
540
- <div className={styles.formGroup}>
541
- <label htmlFor="whatMakesYouReliable" className={styles.label}>
542
- {t('whatMakesYouReliable')} *
543
- </label>
544
- <textarea
545
- id="whatMakesYouReliable"
546
- value={whatMakesYouReliable}
547
- onChange={(e) => setWhatMakesYouReliable(e.target.value)}
548
- className={`${styles.input} ${styles.textarea}`}
549
- disabled={submitting}
550
- required
551
- />
552
- </div>
553
-
554
- <div className={styles.formGroup}>
555
- <label className={styles.label}>
556
- {t('resume')} *
557
- </label>
558
- <div className={`${styles.fileInput} ${submitting ? styles.fileInputDisabled : ''}`}>
559
- <input
560
- id="resume-file"
561
- type="file"
562
- accept=".pdf,.doc,.docx"
563
- onChange={(e) => setResumeFile(e.target.files?.[0] ?? null)}
564
- disabled={submitting}
565
- className={styles.fileInputHidden}
566
- />
567
- <label htmlFor="resume-file" className={styles.fileInputButton}>
568
- {t('chooseFile')}
569
- </label>
570
- {resumeFile && <div className={styles.fileName}>{resumeFile.name}</div>}
571
- </div>
572
- </div>
573
-
574
- <div className={styles.formGroup}>
575
- <label className={styles.label}>
576
- {t('coverLetter')}
577
- </label>
578
- <div className={`${styles.fileInput} ${submitting ? styles.fileInputDisabled : ''}`}>
579
- <input
580
- id="cover-letter-file"
581
- type="file"
582
- accept=".pdf,.doc,.docx"
583
- onChange={(e) => setCoverLetterFile(e.target.files?.[0] ?? null)}
584
- disabled={submitting}
585
- className={styles.fileInputHidden}
586
- />
587
- <label htmlFor="cover-letter-file" className={styles.fileInputButton}>
588
- {t('chooseFile')}
589
- </label>
590
- {coverLetterFile && <div className={styles.fileName}>{coverLetterFile.name}</div>}
591
- </div>
592
- </div>
593
-
594
- {error && <div className={styles.error}>{error}</div>}
595
-
596
- <div className={styles.footer}>
597
- <Button
598
- variant={submitting ? 'disabled' : 'primary'}
599
- hoverColor={ButtonHoverColor.Turquoise}
600
- onClick={handleSubmit}
601
- >
602
- {t('submit')}
603
- </Button>
604
- </div>
605
- </form>
606
- )}
607
- </div>
608
- </div>
609
- <div className={styles.rightColumn}>
610
- <p className={styles.rightColumnText}>Good people.</p>
611
- <p className={styles.rightColumnText}>Epic journeys.</p>
612
- <p className={styles.rightColumnText}>Real impact.</p>
613
- </div>
614
- </div>
615
- </div>
616
- </div>
617
- );
618
- }
619
-
620
- export { JOB_ID_GUEST_EXPERIENCE };