@openeventkit/event-site 2.0.76 → 2.0.77

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openeventkit/event-site",
3
3
  "description": "Event Site",
4
- "version": "2.0.76",
4
+ "version": "2.0.77",
5
5
  "author": "Tipit LLC",
6
6
  "dependencies": {
7
7
  "@mui/base": "^5.0.0-alpha.114",
@@ -78,7 +78,7 @@
78
78
  "netlify-cms-app": "^2.15.72",
79
79
  "netlify-cms-lib-widgets": "^1.8.0",
80
80
  "node-sass-utils": "^1.1.3",
81
- "openstack-uicore-foundation": "4.1.55",
81
+ "openstack-uicore-foundation": "4.1.57",
82
82
  "path-browserify": "^1.0.1",
83
83
  "prop-types": "^15.6.0",
84
84
  "react": "^18.2.0",
@@ -120,7 +120,7 @@
120
120
  "stream-browserify": "^3.0.0",
121
121
  "stream-chat": "^2.7.2",
122
122
  "stream-chat-react": "3.1.7",
123
- "summit-registration-lite": "5.0.13",
123
+ "summit-registration-lite": "5.0.15",
124
124
  "superagent": "8.0.9",
125
125
  "sweetalert2": "^9.17.0",
126
126
  "upcoming-events-widget": "3.0.5",
@@ -0,0 +1,51 @@
1
+ import {
2
+ getAccessToken,
3
+ clearAccessToken,
4
+ } from 'openstack-uicore-foundation/lib/security/methods';
5
+
6
+ import {
7
+ getRequest,
8
+ createAction,
9
+ startLoading,
10
+ stopLoading,
11
+ } from 'openstack-uicore-foundation/lib/utils/actions';
12
+
13
+ import { customErrorHandler } from '../utils/customErrorHandler';
14
+
15
+ export const GET_ATTENDEE_DATA = 'GET_ATTENDEE_DATA';
16
+ export const REQUEST_ATTENDEE_DATA = 'REQUEST_ATTENDEE_DATA';
17
+
18
+ export const getAttendeeData = (attendeeId) => async (dispatch, getState) => {
19
+
20
+ let accessToken;
21
+ try {
22
+ accessToken = await getAccessToken();
23
+ } catch (e) {
24
+ console.log('getAccessToken error: ', e);
25
+ return Promise.reject();
26
+ }
27
+
28
+ let params = {
29
+ access_token: accessToken,
30
+ expand: 'tickets,tickets.owner,extra_questions'
31
+ };
32
+
33
+ dispatch(startLoading());
34
+
35
+ return getRequest(
36
+ createAction(REQUEST_ATTENDEE_DATA),
37
+ createAction(GET_ATTENDEE_DATA),
38
+ `${window.API_BASE_URL}/api/v1/summits/${window.SUMMIT_ID}/attendees/${attendeeId}/me`,
39
+ customErrorHandler
40
+ )(params)(dispatch)
41
+ .then((payload) => {
42
+ dispatch(stopLoading())
43
+ return payload;
44
+ })
45
+ .catch((e) => {
46
+ dispatch(stopLoading());
47
+ console.log('ERROR: ', e);
48
+ clearAccessToken();
49
+ return (e);
50
+ });
51
+ }
@@ -16,7 +16,7 @@ import { customErrorHandler } from '../utils/customErrorHandler';
16
16
 
17
17
  export const GET_EXTRA_QUESTIONS = 'GET_EXTRA_QUESTIONS';
18
18
 
19
- export const getExtraQuestions = () => async (dispatch, getState) => {
19
+ export const getExtraQuestions = (attendeeId = null) => async (dispatch, getState) => {
20
20
 
21
21
  dispatch(startLoading());
22
22
 
@@ -28,7 +28,7 @@ export const getExtraQuestions = () => async (dispatch, getState) => {
28
28
  return Promise.reject(e);
29
29
  }
30
30
 
31
- let apiUrl = URI(`${window.API_BASE_URL}/api/v1/summits/${window.SUMMIT_ID}/attendees/me/allowed-extra-questions`);
31
+ let apiUrl = URI(`${window.API_BASE_URL}/api/v1/summits/${window.SUMMIT_ID}/attendees/${attendeeId ? attendeeId : 'me'}/allowed-extra-questions`);
32
32
  apiUrl.addQuery('expand', '*sub_question_rules,*sub_question,*values')
33
33
  apiUrl.addQuery('access_token', accessToken);
34
34
  apiUrl.addQuery('order', 'order');
@@ -434,7 +434,7 @@ export const updatePassword = (password) => async (dispatch) => {
434
434
  });
435
435
  }
436
436
 
437
- export const saveAttendeeQuestions = (values) => async (dispatch, getState) => {
437
+ export const saveAttendeeQuestions = (values, ticketId = null) => async (dispatch, getState) => {
438
438
 
439
439
  const { userState: { userProfile: { summit_tickets } } } = getState();
440
440
 
@@ -465,7 +465,7 @@ export const saveAttendeeQuestions = (values) => async (dispatch, getState) => {
465
465
  return putRequest(
466
466
  null,
467
467
  createAction(UPDATE_EXTRA_QUESTIONS),
468
- `${window.API_BASE_URL}/api/v1/summits/all/orders/all/tickets/${summit_tickets[0].id}`,
468
+ `${window.API_BASE_URL}/api/v1/summits/all/orders/all/tickets/${ticketId ? ticketId : summit_tickets[0].id}`,
469
469
  normalizedEntity,
470
470
  customErrorHandler
471
471
  )(params)(dispatch).then(() => {
@@ -112,14 +112,14 @@ const RegistrationLiteComponent = ({
112
112
  const inPersonDisclaimer = getSettingByKey(MARKETING_SETTINGS_KEYS.registrationInPersonDisclaimer);
113
113
  const allowPromoCodes = !!Number(getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteAllowPromoCodes));
114
114
  const companyDDLPlaceholder = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteCompanyDDLPlaceholder);
115
- const showCompanyInputDefaultOptions = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteShowCompanyInputDefaultOptions)
116
- const showCompanyInput = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteShowCompanyInput)
117
- const initialOrderComplete1stParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteInitialOrderComplete1stParagraph)
118
- const initialOrderComplete2ndParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteInitialOrderComplete2ndParagraph)
119
- const initialOrderCompleteButton = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteInitialOrderCompleteButton)
120
- const orderComplete1stParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteOrderComplete1stParagraph)
121
- const orderComplete2ndParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteOrderComplete2ndParagraph)
122
- const orderCompleteButton = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteOrderCompleteButton)
115
+ const showCompanyInputDefaultOptions = !!Number(getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteShowCompanyInputDefaultOptions));
116
+ const showCompanyInput = !!Number(getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteShowCompanyInput));
117
+ const initialOrderComplete1stParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteInitialOrderComplete1stParagraph);
118
+ const initialOrderComplete2ndParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteInitialOrderComplete2ndParagraph);
119
+ const initialOrderCompleteButton = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteInitialOrderCompleteButton);
120
+ const orderComplete1stParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteOrderComplete1stParagraph);
121
+ const orderComplete2ndParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteOrderComplete2ndParagraph);
122
+ const orderCompleteButton = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteOrderCompleteButton);
123
123
  const noAllowedTicketsMessage = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteNoAllowedTicketsMessage);
124
124
 
125
125
  const widgetProps = {
@@ -143,18 +143,16 @@ const RegistrationLiteComponent = ({
143
143
  getUserProfile().catch((e) => console.log("getUserProfile error. Not logged in?"));
144
144
  setIsActive(false);
145
145
  },
146
- goToExtraQuestions: () => {
147
- navigate("/a/extra-questions");
146
+ goToExtraQuestions: (attendeeId) => {
147
+ navigate(`/a/extra-questions${attendeeId ? `/#attendee=${attendeeId}` : ''}`);
148
148
  },
149
149
  goToEvent: () => navigate("/a/"),
150
150
  goToRegistration: () => navigate(`${getEnvVariable(REGISTRATION_BASE_URL)}/a/${summit.slug}`),
151
151
  goToMyOrders: () => navigate("/a/my-tickets"),
152
- completedExtraQuestions: async (order) => {
153
- const currentUserTicket = order?.tickets.find(t => t?.owner?.email == userProfile?.email);
154
- const currentAttendee = attendee ? attendee : (currentUserTicket ? currentUserTicket?.owner : null);
155
- if(!currentAttendee) return true;
156
- await getExtraQuestions();
157
- return checkRequireExtraQuestionsByAttendee(currentAttendee);
152
+ completedExtraQuestions: async (attendee) => {
153
+ if(!attendee) return true;
154
+ await getExtraQuestions(attendee?.id);
155
+ return checkRequireExtraQuestionsByAttendee(attendee);
158
156
  },
159
157
  onPurchaseComplete: (order) => {
160
158
  // check if it"s necessary to update profile
@@ -188,8 +186,8 @@ const RegistrationLiteComponent = ({
188
186
  orderComplete2ndParagraph: orderComplete2ndParagraph,
189
187
  orderCompleteButton: orderCompleteButton,
190
188
  noAllowedTicketsMessage: noAllowedTicketsMessage,
191
- showCompanyInput: showCompanyInput.toString().toLowerCase() == "1",
192
- showCompanyInputDefaultOptions: showCompanyInputDefaultOptions.toString().toLowerCase() == "1",
189
+ showCompanyInput: showCompanyInput,
190
+ showCompanyInputDefaultOptions: showCompanyInputDefaultOptions,
193
191
  };
194
192
 
195
193
  const { registerButton } = marketingPageSettings.hero.buttons;
@@ -14,7 +14,6 @@ import ShowOpenRoute from "../../routes/ShowOpenRoute";
14
14
  import WithBadgeRoute from "../../routes/WithBadgeRoute";
15
15
  import PosterDetailPage from "../../templates/poster-detail-page";
16
16
  import MyTicketsPage from "../../templates/my-tickets-page";
17
- import WithTicketRoute from "../../routes/WithTicketRoute";
18
17
  import withRealTimeUpdates from "../../utils/real_time_updates/withRealTimeUpdates";
19
18
  import withFeedsWorker from "../../utils/withFeedsWorker";
20
19
  import Seo from "../../components/Seo";
@@ -38,9 +37,7 @@ const App = ({ isLoggedUser, user, summitPhase, allowClick = true }) => {
38
37
  <WithAuthRoute path="/" isLoggedIn={isLoggedUser} location={location}>
39
38
  <MyTicketsPage path="/my-tickets" isLoggedIn={isLoggedUser} user={user} location={location} />
40
39
  <FullProfilePage path="/profile" summitPhase={summitPhase} isLoggedIn={isLoggedUser} user={user} location={location} />
41
- <WithTicketRoute path="/extra-questions" location={location}>
42
- <ExtraQuestionsPage path="/" isLoggedIn={isLoggedUser} user={user} location={location} />
43
- </WithTicketRoute>
40
+ <ExtraQuestionsPage path="/extra-questions" isLoggedIn={isLoggedUser} user={user} location={location} />
44
41
  <WithAuthzRoute path="/" summitPhase={summitPhase} isLoggedIn={isLoggedUser} user={user} location={location}>
45
42
  <PostersPage path="/posters" trackGroupId={0} location={location} />
46
43
  <PostersPage path="/posters/:trackGroupId" location={location} />
@@ -0,0 +1,38 @@
1
+ import { LOGOUT_USER } from 'openstack-uicore-foundation/lib/security/actions';
2
+ import { START_LOADING, STOP_LOADING } from "openstack-uicore-foundation/lib/utils/actions";
3
+ import {
4
+ GET_ATTENDEE_DATA, REQUEST_ATTENDEE_DATA
5
+ } from '../actions/extra-questions-actions';
6
+ import { RESET_STATE } from '../actions/base-actions-definitions';
7
+ import { UPDATE_EXTRA_QUESTIONS } from '../actions/user-actions';
8
+
9
+ const DEFAULT_STATE = {
10
+ loading: false,
11
+ attendee: null
12
+ }
13
+
14
+ const extraQuestionReducer = (state = DEFAULT_STATE, action) => {
15
+ const { type, payload } = action;
16
+ switch (type) {
17
+ case RESET_STATE:
18
+ case UPDATE_EXTRA_QUESTIONS:
19
+ case LOGOUT_USER: {
20
+ return DEFAULT_STATE;
21
+ }
22
+ case START_LOADING:
23
+ return { ...state, loading: true };
24
+ case STOP_LOADING:
25
+ return { ...state, loading: false };
26
+ case REQUEST_ATTENDEE_DATA: {
27
+ return { ...state, attendee: null }
28
+ }
29
+ case GET_ATTENDEE_DATA: {
30
+ const attendee = payload.response;
31
+ return { ...state, attendee }
32
+ }
33
+ default:
34
+ return state;
35
+ }
36
+ };
37
+
38
+ export default extraQuestionReducer;
@@ -13,6 +13,7 @@ import presentationsReducer from "../reducers/presentations-reducer";
13
13
  import eventReducer from "../reducers/event-reducer";
14
14
  import speakerReducer from "../reducers/speaker-reducer";
15
15
  import sponsorReducer from "../reducers/sponsor-reducer";
16
+ import extraQuestionReducer from "../reducers/extra-questions-reducer";
16
17
 
17
18
  // get from process.env bc window is not set yet
18
19
  const clientId = process.env.GATSBY_OAUTH2_CLIENT_ID;
@@ -44,6 +45,7 @@ const persistedReducers = persistCombineReducers(config, {
44
45
  summitState: summitReducer,
45
46
  speakerState: speakerReducer,
46
47
  sponsorState: sponsorReducer,
48
+ extraQuestionState: extraQuestionReducer
47
49
  });
48
50
 
49
51
  function appendLoggedUser({ getState }) {
@@ -3,6 +3,12 @@
3
3
  @import "bulma/sass/form/_all.sass";
4
4
 
5
5
  @import "colors.scss";
6
+
7
+ .extraQuestionsAttendeeWarning {
8
+ padding: 2rem 6rem;
9
+ font-weight: bold;
10
+ }
11
+
6
12
  .extraQuestionsContainer {
7
13
 
8
14
  h2, h1, h3{
@@ -1,32 +1,35 @@
1
1
  import React, { useEffect, useState, useRef, useMemo } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { connect } from 'react-redux';
4
- import { navigate } from "gatsby";
5
4
  import Layout from '../components/Layout';
6
5
  import { useFormik } from 'formik';
7
6
  import { useTranslation } from "react-i18next";
8
7
  import * as Yup from 'yup';
8
+ import { isEmpty } from "lodash";
9
9
 
10
10
  import { getExtraQuestions } from '../actions/summit-actions';
11
11
  import { saveAttendeeQuestions } from '../actions/user-actions';
12
12
  import { TICKET_ATTENDEE_KEYS as TicketKeys } from '../components/summit-my-orders-tickets/store/actions/ticket-actions';
13
13
  import { Input, RegistrationCompanyInput, RawHTML } from 'openstack-uicore-foundation/lib/components';
14
+ import FragmentParser from "openstack-uicore-foundation/lib/utils/fragment-parser";
14
15
  import QuestionsSet from 'openstack-uicore-foundation/lib/utils/questions-set';
15
16
  import ExtraQuestionsForm from 'openstack-uicore-foundation/lib/components/extra-questions';
16
17
 
17
18
  import { DefaultScrollBehaviour as ScrollBehaviour } from '@utils/scroll';
18
19
 
19
20
  import styles from '../styles/extra-questions.module.scss';
21
+ import { getAttendeeData } from '../actions/extra-questions-actions';
22
+ import HeroComponent from "../components/HeroComponent";
20
23
 
21
24
  const noOpFn = () => {};
22
25
 
23
- export const ExtraQuestionsPageTemplate = ({ user, summit, extraQuestions, saveAttendeeQuestions }) => {
26
+ export const ExtraQuestionsPageTemplate = ({ user, summit, extraQuestions, attendee, attendeeId, saveAttendeeQuestions, someoneElseLoaded }) => {
24
27
 
25
28
  const { t } = useTranslation();
26
29
  const formRef = useRef(null);
27
30
  const [triedSubmitting, setTriedSubmitting] = useState(false);
28
31
 
29
- const ticket = user.summit_tickets.length > 0 ? user.summit_tickets[user.summit_tickets.length - 1] : null;
32
+ const ticket = attendee ? attendee.tickets[0] : user.summit_tickets.length > 0 ? user.summit_tickets[user.summit_tickets.length - 1] : null;
30
33
  const hasExtraQuestions = extraQuestions.length > 0;
31
34
 
32
35
  const initialValues = useMemo(() => {
@@ -69,7 +72,8 @@ export const ExtraQuestionsPageTemplate = ({ user, summit, extraQuestions, saveA
69
72
 
70
73
  const handleSubmit = (values, formikHelpers) => {
71
74
  formikHelpers.setSubmitting(true);
72
- saveAttendeeQuestions(values).then(() => {
75
+ const ticketId = attendee ? attendee.tickets[0]?.id : null;
76
+ saveAttendeeQuestions(values, ticketId).then(() => {
73
77
  formikHelpers.setSubmitting(false);
74
78
  });
75
79
  };
@@ -141,133 +145,145 @@ export const ExtraQuestionsPageTemplate = ({ user, summit, extraQuestions, saveA
141
145
  validateForm();
142
146
  };
143
147
 
144
- if (!ticket) {
145
- navigate('/');
146
- return null;
148
+ if ((!ticket && !attendeeId) || (attendeeId && someoneElseLoaded === false)) {
149
+ return <HeroComponent title={"Sorry. You don't have a ticket for this event."} redirectTo={"/"} />;
150
+ }
151
+
152
+ const getAttendeeFullname = (attendee) => {
153
+ return !isEmpty(attendee.first_name) && !isEmpty(attendee.last_name) ? `${attendee.first_name} ${attendee.last_name}` : attendee.email
147
154
  }
148
155
 
149
156
  return (
150
- <div className={`content columns ${styles.extraQuestionsContainer}`}>
151
- <div className="column is-three-fifths is-offset-one-fifth px-6-desktop py-6-desktop mb-6">
152
- <h2>Attendee Information</h2>
153
- <div className="columns is-multiline pt-4 pb-5">
154
- <div className={`column is-full-mobile is-half ${styles.extraQuestion}`}>
155
- <label htmlFor={TicketKeys.firstName}>First Name</label>
156
- <Input
157
- id={TicketKeys.firstName}
158
- name={TicketKeys.firstName}
159
- className="form-control"
160
- type="text"
161
- placeholder={'Your First Name'}
162
- value={formik.values[TicketKeys.firstName]}
163
- onBlur={formik.handleBlur}
164
- onChange={!!initialValues[TicketKeys.firstName] ? noOpFn : formik.handleChange}
165
- disabled={!!initialValues[TicketKeys.firstName]}
166
- />
167
- {(formik.touched[TicketKeys.firstName] || triedSubmitting) && formik.errors[TicketKeys.firstName] &&
168
- <p className={styles.errorLabel}>{t("ticket_popup.edit_required")}</p>
169
- }
170
- </div>
171
- <div className={`column is-full-mobile is-half ${styles.extraQuestion}`}>
172
- <label htmlFor={TicketKeys.lastName}>Last Name</label>
173
- <Input
174
- id={TicketKeys.lastName}
175
- name={TicketKeys.lastName}
176
- className="form-control"
177
- type="text"
178
- placeholder={'Your Last Name'}
179
- value={formik.values[TicketKeys.lastName]}
180
- onBlur={formik.handleBlur}
181
- onChange={!!initialValues[TicketKeys.lastName] ? noOpFn : formik.handleChange}
182
- disabled={!!initialValues[TicketKeys.lastName]}
183
- />
184
- {(formik.touched[TicketKeys.lastName] || triedSubmitting) && formik.errors[TicketKeys.lastName] &&
185
- <p className={styles.errorLabel}>{t("ticket_popup.edit_required")}</p>
186
- }
187
- </div>
188
- <div className={`column is-full-mobile is-half ${styles.extraQuestion}`}>
189
- <label htmlFor={TicketKeys.email}>Email</label>
190
- <Input
191
- id={TicketKeys.email}
192
- name={TicketKeys.email}
193
- className="form-control"
194
- type="text"
195
- value={initialValues[TicketKeys.email]}
196
- disabled={true}
197
- />
198
- </div>
199
- <div className={`column is-full-mobile is-half ${styles.extraQuestion}`}>
200
- <label htmlFor={TicketKeys.company}>Company</label>
201
- <RegistrationCompanyInput
202
- id={TicketKeys.company}
203
- name={TicketKeys.company}
204
- summitId={summit.id}
205
- placeholder={'Your Company'}
206
- value={formik.values[TicketKeys.company]}
207
- onBlur={formik.handleBlur}
208
- onChange={!!initialValues[TicketKeys.company].name ? noOpFn : formik.handleChange}
209
- disabled={!!initialValues[TicketKeys.company].name}
210
- tabSelectsValue={false}
211
- />
212
- {(formik.touched[TicketKeys.company] || triedSubmitting) && formik.errors[TicketKeys.company] &&
213
- <p className={styles.errorLabel}>{t("ticket_popup.edit_required")}</p>
214
- }
215
- </div>
157
+ <>
158
+ {attendee &&
159
+ <div className={styles.extraQuestionsAttendeeWarning}>
160
+ {`Attention: The info below is for ${getAttendeeFullname(attendee)}. No additional action is required if you
161
+ prefer ${attendee.first_name || attendee.email} to complete this info; they have received an email with instructions.
162
+ You can manage this ticket on the "My Orders / Tickets" page.`}
216
163
  </div>
217
- { hasExtraQuestions &&
218
- <>
219
- <h2 className="mb-3">Additional Information</h2>
220
- <p>Please answer these additional questions.</p>
221
- <ExtraQuestionsForm
222
- extraQuestions={extraQuestions}
223
- userAnswers={formik.values[TicketKeys.extraQuestions]}
224
- onAnswerChanges={onExtraQuestionsAnswersSet}
225
- ref={formRef}
226
- allowExtraQuestionsEdit={summit.allow_update_attendee_extra_questions}
227
- questionContainerClassName={`columns is-multiline ${styles.extraQuestion} pt-3`}
228
- questionLabelContainerClassName={'column is-full pb-0'}
229
- questionControlContainerClassName={`column is-full pt-0`}
230
- shouldScroll2FirstError={false}
231
- onError={handleExtraQuestionError}
232
- />
233
- </>
234
- }
235
- { summit.registration_disclaimer_content &&
236
- <div className="columns">
237
- <div className={`column ${styles.extraQuestion} abc-checkbox`}>
238
- <input
239
- id={TicketKeys.disclaimerAccepted}
240
- name={TicketKeys.disclaimerAccepted}
241
- type="checkbox"
242
- onBlur={formik.handleBlur}
243
- onChange={(e) =>
244
- formik.setFieldTouched(TicketKeys.disclaimerAccepted, true) && formik.handleChange(e)
164
+ }
165
+ <div className={`content columns ${styles.extraQuestionsContainer}`}>
166
+ <div className="column is-three-fifths is-offset-one-fifth px-6-desktop py-6-desktop mb-6">
167
+ <h2>Attendee Information</h2>
168
+ <div className="columns is-multiline pt-4 pb-5">
169
+ <div className={`column is-full-mobile is-half ${styles.extraQuestion}`}>
170
+ <label htmlFor={TicketKeys.firstName}>First Name</label>
171
+ <Input
172
+ id={TicketKeys.firstName}
173
+ name={TicketKeys.firstName}
174
+ className="form-control"
175
+ type="text"
176
+ placeholder={'Your First Name'}
177
+ value={formik.values[TicketKeys.firstName]}
178
+ onBlur={formik.handleBlur}
179
+ onChange={!!initialValues[TicketKeys.firstName] ? noOpFn : formik.handleChange}
180
+ disabled={!!initialValues[TicketKeys.firstName]}
181
+ />
182
+ {(formik.touched[TicketKeys.firstName] || triedSubmitting) && formik.errors[TicketKeys.firstName] &&
183
+ <p className={styles.errorLabel}>{t("ticket_popup.edit_required")}</p>
245
184
  }
246
- checked={formik.values[TicketKeys.disclaimerAccepted]}
185
+ </div>
186
+ <div className={`column is-full-mobile is-half ${styles.extraQuestion}`}>
187
+ <label htmlFor={TicketKeys.lastName}>Last Name</label>
188
+ <Input
189
+ id={TicketKeys.lastName}
190
+ name={TicketKeys.lastName}
191
+ className="form-control"
192
+ type="text"
193
+ placeholder={'Your Last Name'}
194
+ value={formik.values[TicketKeys.lastName]}
195
+ onBlur={formik.handleBlur}
196
+ onChange={!!initialValues[TicketKeys.lastName] ? noOpFn : formik.handleChange}
197
+ disabled={!!initialValues[TicketKeys.lastName]}
198
+ />
199
+ {(formik.touched[TicketKeys.lastName] || triedSubmitting) && formik.errors[TicketKeys.lastName] &&
200
+ <p className={styles.errorLabel}>{t("ticket_popup.edit_required")}</p>
201
+ }
202
+ </div>
203
+ <div className={`column is-full-mobile is-half ${styles.extraQuestion}`}>
204
+ <label htmlFor={TicketKeys.email}>Email</label>
205
+ <Input
206
+ id={TicketKeys.email}
207
+ name={TicketKeys.email}
208
+ className="form-control"
209
+ type="text"
210
+ value={initialValues[TicketKeys.email]}
211
+ disabled={true}
212
+ />
213
+ </div>
214
+ <div className={`column is-full-mobile is-half ${styles.extraQuestion}`}>
215
+ <label htmlFor={TicketKeys.company}>Company</label>
216
+ <RegistrationCompanyInput
217
+ id={TicketKeys.company}
218
+ name={TicketKeys.company}
219
+ summitId={summit.id}
220
+ placeholder={'Your Company'}
221
+ value={formik.values[TicketKeys.company]}
222
+ onBlur={formik.handleBlur}
223
+ onChange={!!initialValues[TicketKeys.company].name ? noOpFn : formik.handleChange}
224
+ disabled={!!initialValues[TicketKeys.company].name}
225
+ tabSelectsValue={false}
226
+ />
227
+ {(formik.touched[TicketKeys.company] || triedSubmitting) && formik.errors[TicketKeys.company] &&
228
+ <p className={styles.errorLabel}>{t("ticket_popup.edit_required")}</p>
229
+ }
230
+ </div>
231
+ </div>
232
+ { hasExtraQuestions &&
233
+ <>
234
+ <h2 className="mb-3">Additional Information</h2>
235
+ <p>Please answer these additional questions.</p>
236
+ <ExtraQuestionsForm
237
+ extraQuestions={extraQuestions}
238
+ userAnswers={formik.values[TicketKeys.extraQuestions]}
239
+ onAnswerChanges={onExtraQuestionsAnswersSet}
240
+ ref={formRef}
241
+ allowExtraQuestionsEdit={summit.allow_update_attendee_extra_questions}
242
+ questionContainerClassName={`columns is-multiline ${styles.extraQuestion} pt-3`}
243
+ questionLabelContainerClassName={'column is-full pb-0'}
244
+ questionControlContainerClassName={`column is-full pt-0`}
245
+ shouldScroll2FirstError={false}
246
+ onError={handleExtraQuestionError}
247
247
  />
248
- <label htmlFor={TicketKeys.disclaimerAccepted}>
249
- {summit.registration_disclaimer_mandatory && <b> *</b>}
250
- </label>
251
- {(formik.touched[TicketKeys.disclaimerAccepted] || triedSubmitting) && formik.errors[TicketKeys.disclaimerAccepted] &&
252
- <p className={styles.errorLabel}>{t("ticket_popup.edit_required")}</p>
253
- }
254
- <div className="mt-3">
255
- <RawHTML>
256
- {summit.registration_disclaimer_content}
257
- </RawHTML>
248
+ </>
249
+ }
250
+ { summit.registration_disclaimer_content &&
251
+ <div className="columns">
252
+ <div className={`column ${styles.extraQuestion} abc-checkbox`}>
253
+ <input
254
+ id={TicketKeys.disclaimerAccepted}
255
+ name={TicketKeys.disclaimerAccepted}
256
+ type="checkbox"
257
+ onBlur={formik.handleBlur}
258
+ onChange={(e) =>
259
+ formik.setFieldTouched(TicketKeys.disclaimerAccepted, true) && formik.handleChange(e)
260
+ }
261
+ checked={formik.values[TicketKeys.disclaimerAccepted]}
262
+ />
263
+ <label htmlFor={TicketKeys.disclaimerAccepted}>
264
+ {summit.registration_disclaimer_mandatory && <b> *</b>}
265
+ </label>
266
+ {(formik.touched[TicketKeys.disclaimerAccepted] || triedSubmitting) && formik.errors[TicketKeys.disclaimerAccepted] &&
267
+ <p className={styles.errorLabel}>{t("ticket_popup.edit_required")}</p>
268
+ }
269
+ <div className="mt-3">
270
+ <RawHTML>
271
+ {summit.registration_disclaimer_content}
272
+ </RawHTML>
273
+ </div>
258
274
  </div>
259
275
  </div>
276
+ }
277
+ <button
278
+ className={`${styles.buttonSave} button is-large`}
279
+ disabled={formik.isSubmitting}
280
+ onClick={triggerSubmit}>
281
+ {!formik.isSubmitting && <>Save and Continue</>}
282
+ {formik.isSubmitting && <>Saving...</>}
283
+ </button>
260
284
  </div>
261
- }
262
- <button
263
- className={`${styles.buttonSave} button is-large`}
264
- disabled={formik.isSubmitting}
265
- onClick={triggerSubmit}>
266
- {!formik.isSubmitting && <>Save and Continue</>}
267
- {formik.isSubmitting && <>Saving...</>}
268
- </button>
269
285
  </div>
270
- </div>
286
+ </>
271
287
  )
272
288
  };
273
289
 
@@ -277,13 +293,22 @@ const ExtraQuestionsPage = (
277
293
  user,
278
294
  summit,
279
295
  extraQuestions,
296
+ attendee,
280
297
  saveAttendeeQuestions,
281
298
  getExtraQuestions,
299
+ getAttendeeData
282
300
  }
283
301
  ) => {
284
302
 
303
+ const fragmentParser = new FragmentParser();
304
+
305
+ const attendeeId = fragmentParser.getParam('attendee') || null;
306
+
307
+ const [someoneElseLoaded, setSomeoneElseLoaded] = useState(null);
308
+
285
309
  useEffect(() => {
286
- getExtraQuestions();
310
+ getExtraQuestions(attendeeId);
311
+ if(attendeeId) getAttendeeData(attendeeId).then(()=> setSomeoneElseLoaded(true)).catch(()=> setSomeoneElseLoaded(false));
287
312
  }, [])
288
313
 
289
314
  return (
@@ -292,7 +317,11 @@ const ExtraQuestionsPage = (
292
317
  user={user}
293
318
  summit={summit}
294
319
  extraQuestions={extraQuestions}
295
- saveAttendeeQuestions={saveAttendeeQuestions} />
320
+ attendeeId={attendeeId || null}
321
+ attendee={attendeeId ? attendee : null}
322
+ saveAttendeeQuestions={saveAttendeeQuestions}
323
+ someoneElseLoaded={someoneElseLoaded}
324
+ />
296
325
  </Layout>
297
326
  )
298
327
  }
@@ -307,16 +336,18 @@ ExtraQuestionsPageTemplate.propTypes = {
307
336
  saveAttendeeQuestions: PropTypes.func,
308
337
  }
309
338
 
310
- const mapStateToProps = ({ userState, summitState }) => ({
339
+ const mapStateToProps = ({ userState, summitState, extraQuestionState }) => ({
311
340
  user: userState.userProfile,
312
341
  loading: userState.loading,
313
342
  summit: summitState.summit,
314
343
  extraQuestions: summitState.extra_questions,
344
+ attendee: extraQuestionState.attendee
315
345
  })
316
346
 
317
347
  export default connect(mapStateToProps,
318
348
  {
319
349
  saveAttendeeQuestions,
320
350
  getExtraQuestions,
351
+ getAttendeeData
321
352
  }
322
- )(ExtraQuestionsPage);
353
+ )(ExtraQuestionsPage);