@openeventkit/event-site 2.0.144 → 2.0.146

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.144",
4
+ "version": "2.0.146",
5
5
  "author": "Tipit LLC",
6
6
  "dependencies": {
7
7
  "@fortawesome/fontawesome-svg-core": "^6.5.2",
@@ -30,7 +30,7 @@
30
30
  "@vimeo/player": "^2.16.3",
31
31
  "ably": "^1.2.34",
32
32
  "assert": "^2.1.0",
33
- "attendee-to-attendee-widget": "3.2.0",
33
+ "attendee-to-attendee-widget": "3.2.1-beta.6",
34
34
  "autoprefixer": "10.4.14",
35
35
  "awesome-bootstrap-checkbox": "^1.0.1",
36
36
  "axios": "^0.19.2",
@@ -85,7 +85,7 @@
85
85
  "moment": "^2.27.0",
86
86
  "moment-timezone": "^0.5.31",
87
87
  "object.assign": "^4.1.5",
88
- "openstack-uicore-foundation": "4.1.76",
88
+ "openstack-uicore-foundation": "4.1.90",
89
89
  "path-browserify": "^1.0.1",
90
90
  "prop-types": "^15.6.0",
91
91
  "react": "^18.2.0",
@@ -130,7 +130,7 @@
130
130
  "stream-browserify": "^3.0.0",
131
131
  "stream-chat": "^2.7.2",
132
132
  "stream-chat-react": "3.1.7",
133
- "summit-registration-lite": "5.0.40",
133
+ "summit-registration-lite": "5.0.42",
134
134
  "superagent": "8.0.9",
135
135
  "sweetalert2": "^9.17.0",
136
136
  "upcoming-events-widget": "3.0.7",
@@ -163,7 +163,8 @@ export const fetchSpeakerById = async(summitId, speakerId, accessToken = null) =
163
163
  apiUrl.addQuery('fields', speakers_fields.join(','));
164
164
 
165
165
  return fetch(apiUrl.toString(), {
166
- method: 'GET'
166
+ method: 'GET',
167
+ cache: "no-store",
167
168
  }).then(async (response) => {
168
169
  if (response.status === 200) {
169
170
  return await response.json();
@@ -239,4 +239,20 @@ export const synchEntityData = (
239
239
  dispatch(createAction(RELOAD_EVENT_STATE)(entity));
240
240
  }
241
241
 
242
- }
242
+ // check if it's a presentation to reload event state
243
+ if (entity && entity_type === 'PresentationSpeaker' && entity_operator === 'UPDATE' && event &&
244
+ (
245
+ // current loaded event is a presentation on where speakers is a presenter
246
+ (entity.all_presentations && entity.all_presentations.find(id => id == event?.id))
247
+ ||
248
+ // current loaded event is a presentation on where speakers is a moderator
249
+ (entity.all_moderated_presentations && entity.all_moderated_presentations.find(id => id == event?.id))
250
+ )
251
+ )
252
+ {
253
+ const idx = allIDXEvents[event?.id];
254
+ const updatedEvent = eventsData[idx];
255
+ dispatch(createAction(RELOAD_EVENT_STATE)(updatedEvent));
256
+ }
257
+
258
+ }
@@ -9,6 +9,8 @@ import {
9
9
  stopLoading,
10
10
  } from 'openstack-uicore-foundation/lib/utils/actions';
11
11
 
12
+ import {putOnLocalStorage, getFromLocalStorage} from 'openstack-uicore-foundation/lib/utils/methods';
13
+
12
14
  import {
13
15
  getAccessToken,
14
16
  clearAccessToken,
@@ -23,6 +25,7 @@ import { navigate } from 'gatsby';
23
25
  import { customErrorHandler, customBadgeHandler, voidErrorHandler } from '../utils/customErrorHandler';
24
26
  import { getEnvVariable, SUMMIT_API_BASE_URL, SUMMIT_ID } from "../utils/envVariables";
25
27
  import expiredToken from "../utils/expiredToken";
28
+ import * as Sentry from "@sentry/react";
26
29
 
27
30
  export const GET_DISQUS_SSO = 'GET_DISQUS_SSO';
28
31
  export const GET_USER_PROFILE = 'GET_USER_PROFILE';
@@ -55,11 +58,15 @@ export const REQUEST_INVITATION = 'REQUEST_INVITATION';
55
58
  export const RECEIVE_INVITATION = 'RECEIVE_INVITATION';
56
59
  export const REJECT_INVITATION = 'REJECT_INVITATION';
57
60
 
61
+ const DISQUS_SSO_EXPIRATION = "DISQUS_SSO_EXPIRATION";
62
+
58
63
  // shortName is the unique identifier assigned to a Disqus site.
59
64
  export const getDisqusSSO = (shortName) => async (dispatch, getState) => {
60
65
  const { userState: { disqusSSO } } = getState();
66
+ const almostTwoHours = 1000 * 60 * 60 * 1.9;
67
+ const disqusSsoExpiration = parseInt(getFromLocalStorage(DISQUS_SSO_EXPIRATION)) || 0;
61
68
 
62
- if (disqusSSO !== null) return;
69
+ if (disqusSSO && disqusSsoExpiration > Date.now()) return;
63
70
 
64
71
  let accessToken;
65
72
  try {
@@ -74,11 +81,16 @@ export const getDisqusSSO = (shortName) => async (dispatch, getState) => {
74
81
  createAction(GET_DISQUS_SSO),
75
82
  `${window.IDP_BASE_URL}/api/v1/sso/disqus/${shortName}/profile?access_token=${accessToken}`,
76
83
  customErrorHandler
77
- )({})(dispatch).catch(e => {
78
- console.log('ERROR: ', e);
79
- clearAccessToken();
84
+ )({})(dispatch)
85
+ .then(() => {
86
+ putOnLocalStorage(DISQUS_SSO_EXPIRATION, Date.now() + almostTwoHours)
87
+ })
88
+ .catch(e => {
89
+ console.log('ERROR: ', e);
90
+ Sentry.captureException(e)
91
+ clearAccessToken();
80
92
 
81
- return Promise.reject(e);
93
+ return Promise.reject(e);
82
94
  });
83
95
  }
84
96
 
@@ -34,7 +34,7 @@ const sbAuthProps = {
34
34
 
35
35
  const adminGroups = ["administrators", "super-admins"];
36
36
 
37
- const AttendeesWidgetComponent = ({ user, event, chatSettings }) => {
37
+ const AttendeesWidgetComponent = ({ user, event, summit, chatSettings }) => {
38
38
  const [loading, setLoading] = useState(true);
39
39
 
40
40
  //Deep linking support
@@ -127,11 +127,14 @@ const AttendeesWidgetComponent = ({ user, event, chatSettings }) => {
127
127
  twitterName: twitter_name,
128
128
  wechatUser: wechat_user,
129
129
  },
130
- getBadgeFeatures: () =>
131
- summit_tickets
130
+ getBadgeFeatures: () => {
131
+ const attendeeBadgeFeatureIds = [...new Set(summit_tickets
132
132
  .filter((st) => st.badge)
133
133
  .flatMap((st) => st.badge.features)
134
- .filter((v, i, a) => a.map((item) => item.id).indexOf(v.id) === i),
134
+ .map((feature) => feature.id))]
135
+
136
+ return summit.badge_features_types.filter((bft) => attendeeBadgeFeatureIds.includes(bft.id));
137
+ },
135
138
  bio: bio,
136
139
  showEmail: public_profile_show_email === true,
137
140
  allowChatWithMe: public_profile_allow_chat_with_me === true,
@@ -170,7 +173,7 @@ const AttendeesWidgetComponent = ({ user, event, chatSettings }) => {
170
173
  }
171
174
  },
172
175
  },
173
- summitId: parseInt(getEnvVariable(SUMMIT_ID)),
176
+ summit: summit,
174
177
  height: 400,
175
178
  defaultScope: chatSettings?.defaultScope || scopes.PAGE, //Default attendees filter scope (scopes.PAGE | scopes.SHOW)
176
179
  ...chatProps,
@@ -297,7 +300,9 @@ const AccessTracker = ({ user, isLoggedUser, summitPhase, chatSettings, updateCh
297
300
  showSocialInfo: public_profile_show_social_media_info === true,
298
301
  showBio: public_profile_show_bio === true
299
302
  },
300
- summitId: parseInt(getEnvVariable(SUMMIT_ID)),
303
+ summit: {
304
+ id: parseInt(getEnvVariable(SUMMIT_ID)),
305
+ },
301
306
  keepAliveEnabled: true,
302
307
  updateChatProfileEnabled: updateChatProfileEnabled,
303
308
  ...chatProps,
@@ -313,7 +318,7 @@ const mapStateToProps = ({ loggedUserState, userState, clockState, settingState
313
318
  isLoggedUser: loggedUserState.isLoggedUser,
314
319
  user: userState,
315
320
  summitPhase: clockState.summit_phase,
316
- chatSettings: settingState.widgets.chat,
321
+ chatSettings: settingState.widgets.chat
317
322
  });
318
323
 
319
324
  export default connect(mapStateToProps)(AccessTracker);
@@ -129,10 +129,13 @@ const AuthComponent = ({
129
129
 
130
130
  const sendCode = (email) => {
131
131
  setUserEmail(email);
132
- getPasswordlessCode(email).then(({ response }) => {
132
+ return getPasswordlessCode(email).then(({ response }) => {
133
133
  setOtpLength(response.otp_length);
134
134
  setOtpLogin(true);
135
- });
135
+ }).catch((err) => {
136
+ const errorMessage = err.response?.body?.error || err.message;
137
+ return Promise.reject(new Error(errorMessage));
138
+ })
136
139
  }
137
140
 
138
141
  const siteSettings = useSiteSettings();
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, {useEffect, useState} from "react";
2
2
  import { connect } from "react-redux";
3
3
  import { DiscussionEmbed } from "disqus-react";
4
4
  import { withMarketingSettings, MARKETING_SETTINGS_KEYS } from "@utils/useMarketingSettings";
@@ -6,61 +6,53 @@ import { getEnvVariable, DISQUS_SHORTNAME } from "@utils/envVariables";
6
6
  import { getDisqusSSO } from "../actions/user-actions";
7
7
  import PropTypes from "prop-types";
8
8
 
9
- const DisqusComponent = class extends React.Component {
9
+ const DisqusComponent = ({summit, sponsor, event, disqusSSO, hideMobile, title, style, className, page, skipTo, ...props}) => {
10
+ const [isMobile, setIsMobile] = useState(false);
11
+ const shortname = getEnvVariable(DISQUS_SHORTNAME);
12
+ const { auth: remoteAuthS3, public_key: apiKey } = disqusSSO || {};
13
+ const almostTwoHours = 1000 * 60 * 60 * 1.9;
10
14
 
11
- constructor(props) {
12
- super(props);
15
+ useEffect(() => {
16
+ // Resize Handler
17
+ window.addEventListener('resize', onResize);
18
+ setIsMobile(window.innerWidth <= 768);
13
19
 
14
- this.state = {
15
- isMobile: false
16
- };
20
+ return () => {
21
+ window.removeEventListener('resize', onResize);
22
+ }
23
+ }, []);
17
24
 
18
- this.getIdentifier = this.getIdentifier.bind(this);
19
- this.getTitle = this.getTitle.bind(this);
20
- }
25
+ // check Disqus SSO on every render
26
+ useEffect(() => {
27
+ let disqusSsoInterval = null;
21
28
 
22
- componentWillUnmount() {
23
- window.removeEventListener('resize', this.onResize);
24
- }
29
+ if (shortname) {
30
+ props.getDisqusSSO(shortname);
25
31
 
26
- componentDidMount() {
27
- const shortname = getEnvVariable(DISQUS_SHORTNAME);
28
- if (shortname)
29
- this.props.getDisqusSSO(shortname).catch((e) => console.log(e));
30
-
31
- window.addEventListener('resize', this.onResize);
32
- if (window.innerWidth <= 768) {
33
- this.setState({ isMobile: true })
34
- } else {
35
- this.setState({ isMobile: false })
32
+ // Edge case: if component has not rendered for more than 2hrs, we need to force a SSO token refresh.
33
+ disqusSsoInterval = setInterval(() => {
34
+ props.getDisqusSSO(shortname);
35
+ }, almostTwoHours);
36
36
  }
37
- }
38
37
 
39
- onResize = () => {
40
- if (window.innerWidth <= 768 && this.state.isMobile === false) {
41
- this.setState({ isMobile: true })
42
- }
43
- if (window.innerWidth > 768 && this.state.isMobile === true) {
44
- this.setState({ isMobile: false })
38
+ return () => {
39
+ if (disqusSsoInterval) {
40
+ clearInterval(disqusSsoInterval);
41
+ }
45
42
  }
46
- };
47
-
48
- getIdentifier() {
49
- const {
50
- summit,
51
- page,
52
- sponsor,
53
- event,
54
- getMarketingSettingByKey
55
- } = this.props;
43
+ });
56
44
 
57
- let threadsBy = getMarketingSettingByKey(MARKETING_SETTINGS_KEYS.disqusThreadsBy) ?? "event";
45
+ const onResize = () => {
46
+ setIsMobile(window.innerWidth <= 768);
47
+ };
58
48
 
49
+ const getIdentifier = () => {
50
+ const threadsBy = props.getMarketingSettingByKey(MARKETING_SETTINGS_KEYS.disqusThreadsBy) ?? "event";
59
51
  let identifier = null;
60
52
 
61
53
  if (event) {
62
- let eventExcludes = getMarketingSettingByKey(MARKETING_SETTINGS_KEYS.disqusExcludeEvents) ?? [];
63
- let trackExcludes = getMarketingSettingByKey(MARKETING_SETTINGS_KEYS.disqusExcludeTracks) ?? [];
54
+ const eventExcludes = props.getMarketingSettingByKey(MARKETING_SETTINGS_KEYS.disqusExcludeEvents) ?? [];
55
+ const trackExcludes = props.getMarketingSettingByKey(MARKETING_SETTINGS_KEYS.disqusExcludeTracks) ?? [];
64
56
 
65
57
  identifier = eventExcludes.includes(event.id) ? `summit/${summit.id}/event/${event.id}` : null;
66
58
 
@@ -95,20 +87,12 @@ const DisqusComponent = class extends React.Component {
95
87
  return identifier;
96
88
  }
97
89
 
98
- getTitle() {
99
- const {
100
- summit,
101
- page,
102
- sponsor,
103
- event,
104
- getMarketingSettingByKey
105
- } = this.props;
106
-
90
+ const getTitle = () => {
107
91
  let suffix = '';
108
- const threadsBy = getMarketingSettingByKey(MARKETING_SETTINGS_KEYS.disqusThreadsBy) ?? "event";
92
+ const threadsBy = props.getMarketingSettingByKey(MARKETING_SETTINGS_KEYS.disqusThreadsBy) ?? "event";
109
93
 
110
94
  if (event) {
111
- const trackExcludes = getMarketingSettingByKey(MARKETING_SETTINGS_KEYS.disqusExcludeTracks) ?? [];
95
+ const trackExcludes = props.getMarketingSettingByKey(MARKETING_SETTINGS_KEYS.disqusExcludeTracks) ?? [];
112
96
  if (event.track && event.track.id && (threadsBy === 'track' || trackExcludes.includes(event.track.id))) {
113
97
  suffix += ' - ';
114
98
  suffix += event.track.name;
@@ -133,49 +117,40 @@ const DisqusComponent = class extends React.Component {
133
117
  return `${summit.name}${suffix}`;
134
118
  }
135
119
 
136
- render() {
137
- const { isMobile } = this.state || null;
138
- const { disqusSSO, hideMobile = null } = this.props;
139
-
140
- if (!disqusSSO || (hideMobile !== null && hideMobile === isMobile)) {
141
- return null;
142
- }
120
+ if (!disqusSSO || (hideMobile !== null && hideMobile === isMobile)) {
121
+ return null;
122
+ }
143
123
 
144
- const { auth: remoteAuthS3, public_key: apiKey } = disqusSSO;
145
- const shortname = getEnvVariable(DISQUS_SHORTNAME);
124
+ if (!remoteAuthS3 || !apiKey || !shortname) {
125
+ let error = 'Disqus misconfiguration: ';
126
+ if (!remoteAuthS3) error = ` ${error} ${!remoteAuthS3 ? 'SSO remoteAuthS3 missing' : ''}`;
127
+ if (!apiKey) error = ` ${error} ${!apiKey ? 'SSO apiKey missing' : ''}`;
128
+ if (!shortname) error = ` ${error} ${!shortname ? 'DISQUS_SHORTNAME env var missing' : ''}`;
129
+ return error;
130
+ }
146
131
 
147
- if (!remoteAuthS3 || !apiKey || !shortname) {
148
- let error = 'Disqus misconfiguration: ';
149
- if (!remoteAuthS3) error = ` ${error} ${!remoteAuthS3 ? 'SSO remoteAuthS3 missing' : ''}`;
150
- if (!apiKey) error = ` ${error} ${!apiKey ? 'SSO apiKey missing' : ''}`;
151
- if (!shortname) error = ` ${error} ${!shortname ? 'DISQUS_SHORTNAME env var missing' : ''}`;
152
- return error;
153
- }
132
+ const disqusConfig = {
133
+ url: window.location.href,
134
+ identifier: getIdentifier(),
135
+ title: getTitle(),
136
+ remoteAuthS3: remoteAuthS3,
137
+ apiKey: apiKey
138
+ };
154
139
 
155
- const disqusConfig = {
156
- url: window.location.href,
157
- identifier: this.getIdentifier(),
158
- title: this.getTitle(),
159
- remoteAuthS3: remoteAuthS3,
160
- apiKey: apiKey
161
- };
162
-
163
- const { title, style, className, page, skipTo } = this.props;
164
- const sectionClass = className ? className : style || page === 'marketing-site' ? '' : 'disqus-container';
165
-
166
- return (
167
- <section aria-labelledby={title ? 'disqus-title' : ''} className={sectionClass} style={style}>
168
- <div className="disqus-header">
169
- {skipTo && <a className="sr-only skip-to-next" href={skipTo}>Skip to next section</a>}
170
- {title && <h2 id="disqus-title" className="title">{title}</h2>}
171
- </div>
172
- <DiscussionEmbed
173
- shortname={shortname}
174
- config={disqusConfig}
175
- />
176
- </section>
177
- );
178
- }
140
+ const sectionClass = className ? className : style || page === 'marketing-site' ? '' : 'disqus-container';
141
+
142
+ return (
143
+ <section aria-labelledby={title ? 'disqus-title' : ''} className={sectionClass} style={style}>
144
+ <div className="disqus-header">
145
+ {skipTo && <a className="sr-only skip-to-next" href={skipTo}>Skip to next section</a>}
146
+ {title && <h2 id="disqus-title" className="title">{title}</h2>}
147
+ </div>
148
+ <DiscussionEmbed
149
+ shortname={shortname}
150
+ config={disqusConfig}
151
+ />
152
+ </section>
153
+ );
179
154
  };
180
155
 
181
156
  const mapStateToProps = ({ summitState, userState }) => ({
@@ -119,6 +119,7 @@ const RegistrationLiteComponent = ({
119
119
  const initialOrderComplete1stParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteInitialOrderComplete1stParagraph);
120
120
  const initialOrderComplete2ndParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteInitialOrderComplete2ndParagraph);
121
121
  const initialOrderCompleteButton = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteInitialOrderCompleteButton);
122
+ const orderCompleteTitle = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteOrderCompleteTitle);
122
123
  const orderComplete1stParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteOrderComplete1stParagraph);
123
124
  const orderComplete2ndParagraph = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteOrderComplete2ndParagraph);
124
125
  const orderCompleteButton = getSettingByKey(MARKETING_SETTINGS_KEYS.regLiteOrderCompleteButton);
@@ -187,6 +188,7 @@ const RegistrationLiteComponent = ({
187
188
  initialOrderComplete1stParagraph: initialOrderComplete1stParagraph,
188
189
  initialOrderComplete2ndParagraph: initialOrderComplete2ndParagraph,
189
190
  initialOrderCompleteButton: initialOrderCompleteButton,
191
+ orderCompleteTitle: orderCompleteTitle,
190
192
  orderComplete1stParagraph: orderComplete1stParagraph,
191
193
  orderComplete2ndParagraph: orderComplete2ndParagraph,
192
194
  orderCompleteButton: orderCompleteButton,
@@ -28,13 +28,13 @@ import { DelegatePopup } from '../../DelegatePopup/DelegatePopup';
28
28
  const noop = () => {};
29
29
 
30
30
  export const TicketPopupEditDetailsForm = ({
31
- ticket,
32
- summit,
33
- order,
34
- canEditTicketData,
35
- goToReassignPanel,
36
- context
37
- }) => {
31
+ ticket,
32
+ summit,
33
+ order,
34
+ canEditTicketData,
35
+ goToReassignPanel,
36
+ context
37
+ }) => {
38
38
  const formRef = useRef(null);
39
39
  const { t } = useTranslation();
40
40
  const dispatch = useDispatch();
@@ -53,7 +53,7 @@ export const TicketPopupEditDetailsForm = ({
53
53
  daysUntilReassignDeadline,
54
54
  isUnassigned,
55
55
  allowsDelegate
56
- } = useTicketDetails({ ticket, summit });
56
+ } = useTicketDetails({ ticket, summit });
57
57
 
58
58
  const { onTicketAssignChange } = useTicketAssignedContext();
59
59
 
@@ -73,9 +73,9 @@ export const TicketPopupEditDetailsForm = ({
73
73
  } = ticket.owner || {};
74
74
 
75
75
  const formattedExtraQuestions = extra_questions ?
76
- extra_questions.map(({ question_id, value }) => (
77
- { question_id, value }
78
- )) : [];
76
+ extra_questions.map(({ question_id, value }) => (
77
+ { question_id, value }
78
+ )) : [];
79
79
 
80
80
  return {
81
81
  [TicketKeys.email]: email,
@@ -129,22 +129,22 @@ export const TicketPopupEditDetailsForm = ({
129
129
 
130
130
  if(isDelegating) {
131
131
  dispatch(delegateTicket(params))
132
- .then(() => toggleSaveMessage())
133
- .catch((error) => console.error(error))
134
- .then(() => {
135
- formikHelpers.resetForm({ values });
136
- formikHelpers.setSubmitting(false);
137
- setIsDelegating(false);
138
- });
132
+ .then(() => toggleSaveMessage())
133
+ .catch((error) => console.error(error))
134
+ .then(() => {
135
+ formikHelpers.resetForm({ values });
136
+ formikHelpers.setSubmitting(false);
137
+ setIsDelegating(false);
138
+ });
139
139
  } else {
140
140
  dispatch(editOwnedTicket(params))
141
- .then(() => toggleSaveMessage())
142
- .catch((error) => console.error(error))
143
- .then(() => {
144
- // Note: Need to do this to persist the extra question values
145
- formikHelpers.resetForm({ values });
146
- formikHelpers.setSubmitting(false);
147
- });
141
+ .then(() => toggleSaveMessage())
142
+ .catch((error) => console.error(error))
143
+ .then(() => {
144
+ // Note: Need to do this to persist the extra question values
145
+ formikHelpers.resetForm({ values });
146
+ formikHelpers.setSubmitting(false);
147
+ });
148
148
  }
149
149
 
150
150
  };
@@ -163,16 +163,16 @@ export const TicketPopupEditDetailsForm = ({
163
163
 
164
164
  const handleDelegateAccept = () => {
165
165
  setShowDelegate(false);
166
- setIsDelegating(true);
166
+ setIsDelegating(true);
167
167
  formik.resetForm({
168
168
  values: {
169
- ...formik.values,
170
- [TicketKeys.firstName]: "",
171
- [TicketKeys.lastName]: "",
172
- [TicketKeys.disclaimerAccepted]: false,
173
- [TicketKeys.extraQuestions]: []
169
+ ...formik.values,
170
+ [TicketKeys.firstName]: "",
171
+ [TicketKeys.lastName]: "",
172
+ [TicketKeys.disclaimerAccepted]: false,
173
+ [TicketKeys.extraQuestions]: []
174
174
  }
175
- });
175
+ });
176
176
  };
177
177
 
178
178
  const handleDelegateReject = () => {
@@ -255,46 +255,46 @@ export const TicketPopupEditDetailsForm = ({
255
255
  }
256
256
 
257
257
  return (
258
- <div className="ticket-popup-edit-details-form">
259
- {showSaveMessage &&
258
+ <div className="ticket-popup-edit-details-form">
259
+ {showSaveMessage &&
260
260
  <CSSTransition
261
- unmountOnExit
262
- in={showSaveMessage}
263
- timeout={2000}
264
- classNames="fade-in-out"
261
+ unmountOnExit
262
+ in={showSaveMessage}
263
+ timeout={2000}
264
+ classNames="fade-in-out"
265
265
  >
266
266
  <Alert bsStyle="success" className="ticket-popup-form-alert text-center">
267
267
  {t("tickets.save_message")}
268
268
  </Alert>
269
269
  </CSSTransition>
270
- }
270
+ }
271
271
 
272
- {showUnassignMessage &&
272
+ {showUnassignMessage &&
273
273
  <CSSTransition
274
- unmountOnExit
275
- in={showUnassignMessage}
276
- timeout={2000}
277
- classNames="fade-in-out"
274
+ unmountOnExit
275
+ in={showUnassignMessage}
276
+ timeout={2000}
277
+ classNames="fade-in-out"
278
278
  >
279
279
  <Alert bsStyle="success" className="ticket-popup-form-alert text-center">
280
280
  {t("tickets.unassign_success_message")}
281
281
  </Alert>
282
282
  </CSSTransition>
283
- }
284
-
285
- <div className="ticket-popup-form-body columns is-multiline">
286
-
287
- <div className="attendee-info column is-full">
288
- <h4 className="pb-3">{t("ticket_popup.edit_basic_info")}</h4>
289
- <label htmlFor={TicketKeys.email}>Email</label>
290
- <Input
291
- id={TicketKeys.email}
292
- name={TicketKeys.email}
293
- className="form-control"
294
- value={initialValues[TicketKeys.email]}
295
- disabled={true}
296
- />
297
- {isUserTicketOwner && isReassignable &&
283
+ }
284
+
285
+ <div className="ticket-popup-form-body columns is-multiline">
286
+
287
+ <div className="attendee-info column is-full">
288
+ <h4 className="pb-3">{t("ticket_popup.edit_basic_info")}</h4>
289
+ <label htmlFor={TicketKeys.email}>Email</label>
290
+ <Input
291
+ id={TicketKeys.email}
292
+ name={TicketKeys.email}
293
+ className="form-control"
294
+ value={initialValues[TicketKeys.email]}
295
+ disabled={true}
296
+ />
297
+ {isUserTicketOwner && isReassignable &&
298
298
  <div className="mt-1">
299
299
  <span onClick={() => goToReassignPanel()}>
300
300
  <u>Reassign</u>
@@ -304,124 +304,122 @@ export const TicketPopupEditDetailsForm = ({
304
304
  <u>Unassign</u>
305
305
  </span>
306
306
  </div>
307
- }
308
- </div>
307
+ }
308
+ </div>
309
+
310
+ <div className="attendee-info column is-full">
311
+ <label htmlFor={TicketKeys.firstName}>
312
+ {t("ticket_popup.edit_first_name")}
313
+ {!initialValues[TicketKeys.firstName] && <b> *</b>}
314
+ </label>
315
+ <Input
316
+ id={TicketKeys.firstName}
317
+ name={TicketKeys.firstName}
318
+ className="form-control"
319
+ placeholder={t("ticket_popup.edit_first_name_placeholder")}
320
+ value={formik.values[TicketKeys.firstName]}
321
+ onBlur={formik.handleBlur}
322
+ onChange={!!initialValues[TicketKeys.firstName] && !isDelegating ? noop : formik.handleChange}
323
+ disabled={!!initialValues[TicketKeys.firstName] && !isDelegating}
324
+ />
325
+ {(formik.touched[TicketKeys.firstName] || triedSubmitting) && formik.errors[TicketKeys.firstName] &&
326
+ <p className="error-label">{t("ticket_popup.edit_required")}</p>
327
+ }
328
+ </div>
329
+
330
+ <div className="attendee-info column is-full">
331
+ <label htmlFor={TicketKeys.lastName}>
332
+ {t("ticket_popup.edit_last_name")}
333
+ {!initialValues[TicketKeys.lastName] && <b> *</b>}
334
+ </label>
335
+ <Input
336
+ id={TicketKeys.lastName}
337
+ name={TicketKeys.lastName}
338
+ className="form-control"
339
+ placeholder={t("ticket_popup.edit_last_name_placeholder")}
340
+ value={formik.values[TicketKeys.lastName]}
341
+ onBlur={formik.handleBlur}
342
+ onChange={!!initialValues[TicketKeys.lastName] && !isDelegating ? noop : formik.handleChange}
343
+ disabled={!!initialValues[TicketKeys.lastName] && !isDelegating}
344
+ />
345
+ {(formik.touched[TicketKeys.lastName] || triedSubmitting) && formik.errors[TicketKeys.lastName] &&
346
+ <p className="error-label">{t("ticket_popup.edit_required")}</p>
347
+ }
348
+ </div>
309
349
 
350
+ {allowsDelegate &&
310
351
  <div className="attendee-info column is-full">
311
- <label htmlFor={TicketKeys.firstName}>
312
- {t("ticket_popup.edit_first_name")}
313
- {!initialValues[TicketKeys.firstName] && <b> *</b>}
314
- </label>
315
- <Input
316
- id={TicketKeys.firstName}
317
- name={TicketKeys.firstName}
318
- className="form-control"
319
- placeholder={t("ticket_popup.edit_first_name_placeholder")}
320
- value={formik.values[TicketKeys.firstName]}
321
- onBlur={formik.handleBlur}
322
- onChange={!!initialValues[TicketKeys.firstName] && !isDelegating ? noop : formik.handleChange}
323
- disabled={!!initialValues[TicketKeys.firstName] && !isDelegating}
324
- />
325
- {(formik.touched[TicketKeys.firstName] || triedSubmitting) && formik.errors[TicketKeys.firstName] &&
326
- <p className="error-label">{t("ticket_popup.edit_required")}</p>
327
- }
352
+ <button className="button-text" type='button' onClick={() => setShowDelegate(true)}>Delegate</button>
328
353
  </div>
354
+ }
329
355
 
356
+ {showCompanyInput &&
330
357
  <div className="attendee-info column is-full">
331
- <label htmlFor={TicketKeys.lastName}>
332
- {t("ticket_popup.edit_last_name")}
333
- {!initialValues[TicketKeys.lastName] && <b> *</b>}
358
+ <label htmlFor={TicketKeys.company}>
359
+ {t("ticket_popup.edit_company")}
360
+ {!initialValues[TicketKeys.company].name && <b> *</b>}
334
361
  </label>
335
- <Input
336
- id={TicketKeys.lastName}
337
- name={TicketKeys.lastName}
338
- className="form-control"
339
- placeholder={t("ticket_popup.edit_last_name_placeholder")}
340
- value={formik.values[TicketKeys.lastName]}
341
- onBlur={formik.handleBlur}
342
- onChange={!!initialValues[TicketKeys.lastName] && !isDelegating ? noop : formik.handleChange}
343
- disabled={!!initialValues[TicketKeys.lastName] && !isDelegating}
362
+ <RegistrationCompanyInput
363
+ id={TicketKeys.company}
364
+ name={TicketKeys.company}
365
+ summitId={summit.id}
366
+ placeholder={t("ticket_popup.edit_company_placeholder")}
367
+ value={formik.values[TicketKeys.company]}
368
+ onBlur={formik.handleBlur}
369
+ onChange={!!initialValues[TicketKeys.company].name ? noop : formik.handleChange}
370
+ disabled={!!initialValues[TicketKeys.company].name}
371
+ defaultOptions={showCompanyInputDefaultOptions}
372
+ openMenuOnFocus={showCompanyInputDefaultOptions}
373
+ openMenuOnClick={showCompanyInputDefaultOptions}
374
+ styles={{
375
+ menu: (base) => ({ ...base, zIndex: 9999 }),
376
+ }}
377
+ tabSelectsValue={false}
344
378
  />
345
- {(formik.touched[TicketKeys.lastName] || triedSubmitting) && formik.errors[TicketKeys.lastName] &&
346
- <p className="error-label">{t("ticket_popup.edit_required")}</p>
379
+ {(formik.touched[TicketKeys.company] || triedSubmitting) && formik.errors[TicketKeys.company] &&
380
+ <p className="error-label">{t("ticket_popup.edit_required")}</p>
347
381
  }
348
382
  </div>
383
+ }
349
384
 
350
- {allowsDelegate &&
351
- <div className="attendee-info column is-full">
352
- <button className="button-text" type='button' onClick={() => setShowDelegate(true)}>Delegate</button>
353
- </div>
354
- }
355
-
356
- {showCompanyInput &&
357
- <div className="attendee-info column is-full">
358
- <label htmlFor={TicketKeys.company}>
359
- {t("ticket_popup.edit_company")}
360
- {!initialValues[TicketKeys.company].name && <b> *</b>}
361
- </label>
362
- <RegistrationCompanyInput
363
- id={TicketKeys.company}
364
- name={TicketKeys.company}
365
- summitId={summit.id}
366
- placeholder={t("ticket_popup.edit_company_placeholder")}
367
- value={formik.values[TicketKeys.company]}
368
- onBlur={formik.handleBlur}
369
- onChange={!!initialValues[TicketKeys.company].name ? noop : formik.handleChange}
370
- disabled={!!initialValues[TicketKeys.company].name}
371
- defaultOptions={showCompanyInputDefaultOptions}
372
- openMenuOnFocus={showCompanyInputDefaultOptions}
373
- openMenuOnClick={showCompanyInputDefaultOptions}
374
- menuPortalTarget={document.body}
375
- menuPosition="fixed"
376
- styles={{
377
- menuPortal: (base) => ({ ...base, zIndex: 9999 }),
378
- }}
379
- tabSelectsValue={false}
380
- />
381
- {(formik.touched[TicketKeys.company] || triedSubmitting) && formik.errors[TicketKeys.company] &&
382
- <p className="error-label">{t("ticket_popup.edit_required")}</p>
383
- }
384
- </div>
385
- }
386
-
387
- {(initialValues[TicketKeys.firstName] || initialValues[TicketKeys.lastName] || initialValues[TicketKeys.company].name) &&
385
+ {(initialValues[TicketKeys.firstName] || initialValues[TicketKeys.lastName] || initialValues[TicketKeys.company].name) &&
388
386
  <div className="column is-full pb-5">
389
387
  {t("ticket_popup.assign_note")}
390
388
  </div>
391
- }
389
+ }
392
390
 
393
- {hasExtraQuestions &&
391
+ {hasExtraQuestions &&
394
392
  <div className="column is-full pt-5">
395
393
  <h4 className="pb-2">{t("ticket_popup.edit_preferences")}</h4>
396
394
  <ExtraQuestionsForm
397
- // This key is added to trigger a new render when the extra questions are resetted on delegation
398
- key={formik.values[TicketKeys.extraQuestions].length}
399
- ref={formRef}
400
- extraQuestions={extraQuestions}
401
- userAnswers={formik.values[TicketKeys.extraQuestions]}
402
- onAnswerChanges={onExtraQuestionsAnswersSet}
403
- allowExtraQuestionsEdit={canEditTicketData || isDelegating}
404
- questionContainerClassName={`columns is-multiline extra-question pt-3`}
405
- questionLabelContainerClassName={'column is-full pb-0'}
406
- questionControlContainerClassName={`column is-full pt-0`}
407
- shouldScroll2FirstError={false}
408
- onError={handleExtraQuestionError}
395
+ // This key is added to trigger a new render when the extra questions are resetted on delegation
396
+ key={formik.values[TicketKeys.extraQuestions].length}
397
+ ref={formRef}
398
+ extraQuestions={extraQuestions}
399
+ userAnswers={formik.values[TicketKeys.extraQuestions]}
400
+ onAnswerChanges={onExtraQuestionsAnswersSet}
401
+ allowExtraQuestionsEdit={canEditTicketData || isDelegating}
402
+ questionContainerClassName={`columns is-multiline extra-question pt-3`}
403
+ questionLabelContainerClassName={'column is-full pb-0'}
404
+ questionControlContainerClassName={`column is-full pt-0`}
405
+ shouldScroll2FirstError={false}
406
+ onError={handleExtraQuestionError}
409
407
  />
410
408
  </div>
411
- }
409
+ }
412
410
 
413
- {summit.registration_disclaimer_content &&
411
+ {summit.registration_disclaimer_content &&
414
412
  <div className="column is-full attendee-info abc-checkbox disclaimer mt-3">
415
413
  <div className='input-wrapper'>
416
414
  <input
417
- type="checkbox"
418
- id={TicketKeys.disclaimerAccepted}
419
- name={TicketKeys.disclaimerAccepted}
420
- onBlur={formik.handleBlur}
421
- onChange={(e) =>
422
- formik.setFieldTouched(TicketKeys.disclaimerAccepted, true) && formik.handleChange(e)
423
- }
424
- checked={formik.values[TicketKeys.disclaimerAccepted]}
415
+ type="checkbox"
416
+ id={TicketKeys.disclaimerAccepted}
417
+ name={TicketKeys.disclaimerAccepted}
418
+ onBlur={formik.handleBlur}
419
+ onChange={(e) =>
420
+ formik.setFieldTouched(TicketKeys.disclaimerAccepted, true) && formik.handleChange(e)
421
+ }
422
+ checked={formik.values[TicketKeys.disclaimerAccepted]}
425
423
  />
426
424
  <label htmlFor={TicketKeys.disclaimerAccepted}>
427
425
  {summit.registration_disclaimer_mandatory && <b> *</b>}
@@ -433,36 +431,36 @@ export const TicketPopupEditDetailsForm = ({
433
431
  </RawHTML>
434
432
  </div>
435
433
  {(formik.touched[TicketKeys.disclaimerAccepted] || triedSubmitting) && formik.errors[TicketKeys.disclaimerAccepted] &&
436
- <p className="error-label">{t("ticket_popup.edit_required")}</p>
434
+ <p className="error-label">{t("ticket_popup.edit_required")}</p>
437
435
  }
438
436
  </div>
439
- }
440
- </div>
437
+ }
438
+ </div>
441
439
 
442
- {canSubmitChanges() &&
440
+ {canSubmitChanges() &&
443
441
  <div className="ticket-popup-footer">
444
442
  <button
445
- type="button"
446
- className="btn btn-primary"
447
- disabled={formik.isSubmitting}
448
- onClick={triggerSubmit}
443
+ type="button"
444
+ className="btn btn-primary"
445
+ disabled={formik.isSubmitting}
446
+ onClick={triggerSubmit}
449
447
  >
450
448
  {!formik.isSubmitting && <>{t("ticket_popup.save_changes")}</>}
451
449
  {formik.isSubmitting && <>{t("ticket_popup.saving_changes")}...</>}
452
450
  </button>
453
451
  </div>
454
- }
455
- <ConfirmPopup
456
- isOpen={showConfirm}
457
- popupCase={CONFIRM_POPUP_CASE.UNASSIGN_TICKET}
458
- onAccept={handleConfirmAccept}
459
- onReject={handleConfirmReject}
460
- />
461
- <DelegatePopup
462
- isOpen={showDelegate}
463
- onAccept={handleDelegateAccept}
464
- onReject={handleDelegateReject}
465
- />
466
- </div>
452
+ }
453
+ <ConfirmPopup
454
+ isOpen={showConfirm}
455
+ popupCase={CONFIRM_POPUP_CASE.UNASSIGN_TICKET}
456
+ onAccept={handleConfirmAccept}
457
+ onReject={handleConfirmReject}
458
+ />
459
+ <DelegatePopup
460
+ isOpen={showDelegate}
461
+ onAccept={handleDelegateAccept}
462
+ onReject={handleDelegateReject}
463
+ />
464
+ </div>
467
465
  );
468
466
  };
@@ -26,7 +26,9 @@ export const TicketPopupReassignForm = ({ ticket, summit, order }) => {
26
26
  const [showConfirm, setShowConfirm] = useState(false);
27
27
  const [newAttendeeEmail, setNewAttendeeEmail] = useState('');
28
28
  const [showSaveMessage, setShowSaveMessage] = useState(false);
29
+ const [showErrorMessage, setShowErrorMessage] = useState(false);
29
30
  const [message, setMessage] = useState('')
31
+ const [errorMessage, setErrorMessage] = useState('')
30
32
 
31
33
  const { onTicketAssignChange } = useTicketAssignedContext();
32
34
 
@@ -38,6 +40,11 @@ export const TicketPopupReassignForm = ({ ticket, summit, order }) => {
38
40
  setTimeout(() => setShowSaveMessage(false), 5000);
39
41
  };
40
42
 
43
+ const toggleErrorMessage = () => {
44
+ setTimeout(() => setShowErrorMessage(true), 50);
45
+ setTimeout(() => setShowErrorMessage(false), 5000);
46
+ };
47
+
41
48
  const handleSubmit = (values, formikHelpers) => {
42
49
  setNewAttendeeEmail(values.attendee_email);
43
50
  setShowConfirm(true);
@@ -62,14 +69,17 @@ export const TicketPopupReassignForm = ({ ticket, summit, order }) => {
62
69
 
63
70
  dispatch(changeTicketAttendee({
64
71
  ticket,
65
- message,
72
+ message,
66
73
  order,
67
74
  data: { attendee_email: newAttendeeEmail }
68
75
  })).then((updatedTicket) => {
69
76
  onTicketAssignChange(updatedTicket);
70
77
  toggleSaveMessage();
71
78
  setMessage('');
72
- });
79
+ }).catch((err) => {
80
+ setErrorMessage(err);
81
+ toggleErrorMessage();
82
+ })
73
83
  };
74
84
 
75
85
  const handleConfirmReject = () => {
@@ -83,12 +93,12 @@ export const TicketPopupReassignForm = ({ ticket, summit, order }) => {
83
93
  <form className="ticket-reassign-form" onSubmit={formik.handleSubmit}>
84
94
  <div className="ticket-popup-form-body">
85
95
  {
86
- isTicketPrinted ?
96
+ isTicketPrinted ?
87
97
  <>
88
98
  <p>
89
99
  {t("ticket_popup.reassign_printed_ticket")}
90
100
  </p>
91
- </>
101
+ </>
92
102
  :
93
103
  <>
94
104
  {showSaveMessage && (
@@ -104,6 +114,19 @@ export const TicketPopupReassignForm = ({ ticket, summit, order }) => {
104
114
  </CSSTransition>
105
115
  )}
106
116
 
117
+ {showErrorMessage && (
118
+ <CSSTransition
119
+ unmountOnExit
120
+ in={showErrorMessage}
121
+ timeout={2000}
122
+ classNames="fade-in-out"
123
+ >
124
+ <Alert bsStyle="warning" className="ticket-popup-form-alert text-center">
125
+ {errorMessage}
126
+ </Alert>
127
+ </CSSTransition>
128
+ )}
129
+
107
130
  {!isUserTicketOwner && (
108
131
  <>
109
132
  <p>
@@ -167,4 +190,4 @@ export const TicketPopupReassignForm = ({ ticket, summit, order }) => {
167
190
  />
168
191
  </>
169
192
  )
170
- };
193
+ };
@@ -28,6 +28,7 @@ import { objectToQueryString } from 'openstack-uicore-foundation/lib/utils/metho
28
28
  import { getIdToken } from 'openstack-uicore-foundation/lib/security/methods';
29
29
  import { getUserOrders } from "./order-actions";
30
30
  import { updateProfile } from './user-actions';
31
+ import { processActionError } from './../../util/helpers/index';
31
32
 
32
33
  export const GET_TICKETS = 'GET_TICKETS';
33
34
  export const ASSIGN_TICKET = 'ASSIGN_TICKET';
@@ -49,10 +50,10 @@ export const TICKET_ATTENDEE_KEYS = {
49
50
  extraQuestions: 'extra_questions'
50
51
  }
51
52
 
52
- const customFetchErrorHandler = (response) => {
53
+ const customFetchErrorHandler = (response) => (dispatch) => {
53
54
  let code = response.status;
54
55
  let msg = response.statusText;
55
-
56
+ dispatch(stopLoading());
56
57
  switch (code) {
57
58
  case 403:
58
59
  Swal.fire('ERROR', i18n.t('errors.user_not_authz'), 'warning');
@@ -76,6 +77,24 @@ const customFetchErrorHandler = (response) => {
76
77
  }
77
78
  };
78
79
 
80
+ const customWithout412ErrorHandler = (
81
+ err
82
+ ) => (dispatch) => {
83
+ dispatch(stopLoading());
84
+ switch (err.status) {
85
+ case 403:
86
+ Swal.fire('ERROR', i18n.t('errors.user_not_authz'), 'warning');
87
+ break;
88
+ case 401:
89
+ Swal.fire('ERROR', i18n.t('errors.session_expired'), 'error');
90
+ break;
91
+ case 500:
92
+ Swal.fire('ERROR', i18n.t('errors.server_error'), 'error');
93
+ break;
94
+ }
95
+ };
96
+
97
+
79
98
  export const getUserTickets = ({ page = 1, perPage = 5 }) => async (dispatch, getState, { getAccessToken, apiBaseUrl, loginUrl }) => {
80
99
  const { userState: { userProfile }, summitState: { summit } } = getState();
81
100
 
@@ -229,7 +248,7 @@ export const assignAttendee = ({
229
248
  createAction(ASSIGN_TICKET),
230
249
  `${apiBaseUrl}/api/v1/summits/all/orders/${orderId}/tickets/${ticket.id}/attendee`,
231
250
  normalizedEntity,
232
- authErrorHandler
251
+ customWithout412ErrorHandler
233
252
  )(params)(dispatch).then((newTicket) => {
234
253
  if (reassignOrderId && context === 'ticket-list') {
235
254
  dispatch(getUserTickets({ page: ticketPage }));
@@ -238,9 +257,8 @@ export const assignAttendee = ({
238
257
  dispatch(getTicketsByOrder({ orderId, page: orderTicketsCurrentPage }));
239
258
  }
240
259
  return newTicket;
241
- }).catch(e => {
242
- dispatch(stopLoading());
243
- return (e);
260
+ }).catch(({err}) => {
261
+ processActionError(err);
244
262
  });
245
263
  }
246
264
 
@@ -301,7 +319,7 @@ export const editOwnedTicket = ({
301
319
  `${apiBaseUrl}/api/v1/summits/all/orders/all/tickets/${ticket.id}`,
302
320
  normalizedEntity,
303
321
  authErrorHandler
304
- )(params)(dispatch).then(async () => {
322
+ )(params)(dispatch).then(async () => {
305
323
  const hasManager = ticket.owner?.manager?.id || ticket.owner?.manager_id;
306
324
  // email should match ( only update my profile is ticket belongs to me!)
307
325
  // and if the ticket doesn't have a manager
@@ -392,7 +410,7 @@ export const changeTicketAttendee = ({
392
410
  createAction(REMOVE_TICKET_ATTENDEE),
393
411
  `${apiBaseUrl}/api/v1/summits/all/orders/${orderId}/tickets/${ticket.id}/attendee`,
394
412
  {},
395
- authErrorHandler
413
+ customWithout412ErrorHandler
396
414
  )(params)(dispatch).then(() => {
397
415
  return dispatch(assignAttendee({
398
416
  ticket,
@@ -409,10 +427,8 @@ export const changeTicketAttendee = ({
409
427
  reassignOrderId: orderId,
410
428
  }
411
429
  }));
412
- }).catch((e) => {
413
- console.log('error', e)
414
- dispatch(stopLoading());
415
- return (e);
430
+ }).catch(({err}) => {
431
+ processActionError(err);
416
432
  });
417
433
  };
418
434
 
@@ -573,16 +589,16 @@ export const delegateTicket = ({
573
589
  return putRequest(
574
590
  null,
575
591
  createAction(DELEGATE_TICKET),
576
- `${apiBaseUrl}/api/v1/summits/${summitId}/orders/${orderId}/tickets/${ticket.id}/delegate`,
592
+ `${apiBaseUrl}/api/v1/summits/${summitId}/orders/${orderId}/tickets/${ticket.id}/delegate`,
577
593
  normalizedEntity,
578
- authErrorHandler
594
+ authErrorHandler
579
595
  )(params)(dispatch).then(() => {
580
596
  dispatch(stopLoading());
581
597
  // Note: refresh the list view after updating the ticket.
582
598
  if (context === 'ticket-list') {
583
599
  dispatch(getUserTickets({ page: ticketPage }));
584
600
  } else {
585
- dispatch(getUserOrders({ page: orderPage })).then(() =>
601
+ dispatch(getUserOrders({ page: orderPage })).then(() =>
586
602
  dispatch(getTicketsByOrder({ orderId: ticket.order_id, page: orderTicketsCurrentPage }))
587
603
  );
588
604
  }
@@ -7,3 +7,16 @@ export * from './getFormattedDate';
7
7
  export * from './getFormattedTime';
8
8
  export * from './getWindowScroll';
9
9
  export * from './formatCurrency';
10
+
11
+
12
+ export const processActionError = (err) => {
13
+ if(err?.status == 412) {
14
+ let msg = '';
15
+ for (const [key, value] of Object.entries(err.response.body.errors)) {
16
+ msg += isNaN(key) ? `${key}: ` : "";
17
+ msg += `${value}`;
18
+ }
19
+ throw msg;
20
+ }
21
+ throw err;
22
+ }
@@ -1,7 +1,7 @@
1
1
  import { START_LOADING, STOP_LOADING } from "openstack-uicore-foundation/lib/utils/actions";
2
2
  import { LOGOUT_USER } from "openstack-uicore-foundation/lib/security/actions";
3
3
  import {GET_EVENT_DATA, GET_EVENT_DATA_ERROR, RELOAD_EVENT_STATE, SET_EVENT_LAST_UPDATE, GET_EVENT_STREAMING_INFO} from "../actions/event-actions-definitions";
4
- import {RESET_STATE} from "../actions/base-actions-definitions";
4
+ import {RESET_STATE, SYNC_DATA} from "../actions/base-actions-definitions";
5
5
 
6
6
  const DEFAULT_STATE = {
7
7
  loading: false,
@@ -14,6 +14,7 @@ const eventReducer = (state = DEFAULT_STATE, action) => {
14
14
  const { type, payload } = action
15
15
 
16
16
  switch (type) {
17
+
17
18
  case RESET_STATE:
18
19
  case LOGOUT_USER:
19
20
  {
@@ -32,6 +33,18 @@ const eventReducer = (state = DEFAULT_STATE, action) => {
32
33
  const updatedEvent = event.id === state?.event?.id ? {...state, ...event} : event;
33
34
  return { ...state, loading: false, event: updatedEvent, tokens: null };
34
35
  }
36
+ case SYNC_DATA:{
37
+ // update current event if we have one on data sync
38
+ const {eventsData, eventsIDXData } = payload;
39
+ if(state?.event){
40
+ const idx = eventsIDXData[state?.event?.id] || null;
41
+ if(idx) {
42
+ const updatedEvent = eventsData[idx];
43
+ return {...state, loading: false, event: updatedEvent, tokens: null};
44
+ }
45
+ }
46
+ return state;
47
+ }
35
48
  case GET_EVENT_DATA_ERROR: {
36
49
  return { ...state, loading: false, event: null, tokens: null }
37
50
  }
@@ -98,6 +98,10 @@ button.link {
98
98
  justify-content: space-between;
99
99
  }
100
100
 
101
+ #content-wrapper {
102
+ flex-grow: 1;
103
+ }
104
+
101
105
  header div.current-user {
102
106
  position: absolute;
103
107
  top: 30px;
@@ -67,9 +67,7 @@ export const EventPageTemplate = class extends React.Component {
67
67
 
68
68
  componentDidMount() {
69
69
  const {eventId, event } = this.props;
70
- if (parseInt(event?.id) !== parseInt(eventId)) {
71
- this.props.getEventById(eventId).then(() => this.props.getEventStreamingInfoById(eventId));
72
- }
70
+ this.props.getEventById(eventId).then(() => this.props.getEventStreamingInfoById(eventId));
73
71
  }
74
72
 
75
73
  onError(err){
@@ -200,7 +198,7 @@ export const EventPageTemplate = class extends React.Component {
200
198
  <div className="column px-0 py-0 is-one-quarter is-full-mobile">
201
199
  <DocumentsComponent event={event}/>
202
200
  <AccessTracker/>
203
- <AttendeesWidget user={user} event={event}/>
201
+ <AttendeesWidget user={user} event={event} summit={summit}/>
204
202
  <AdvertiseComponent section="event" column="right"/>
205
203
  </div>
206
204
  </div>
@@ -121,7 +121,7 @@ export const LobbyPageTemplate = class extends React.Component {
121
121
  <div className="column is-one-quarter pb-6">
122
122
  <h2><b>My Info</b></h2>
123
123
  <AccessTracker/>
124
- <AttendeesWidget user={user}/>
124
+ <AttendeesWidget user={user} summit={summit}/>
125
125
  <LiteScheduleComponent
126
126
  id={`lobby_page_lite_schedule_${lastDataSync}`}
127
127
  lastDataSync={lastDataSync}
@@ -56,7 +56,7 @@ const MainColumn = ({ widgets, summitPhase, isLoggedUser, onEventClick, lastData
56
56
  <DisqusComponent page="marketing-site" />
57
57
  </>
58
58
  )}
59
- {image?.display && image?.image.src && (
59
+ {image?.display && image?.image?.src && (
60
60
  <>
61
61
  <h2><b>{image.title}</b></h2>
62
62
  <br/>
@@ -244,7 +244,7 @@ export const PosterDetailPage = ({
244
244
  {poster.meeting_url && <PosterLiveSession poster={poster} ctaText={activityCtaText} />}
245
245
  <DocumentsComponent event={poster} />
246
246
  <AccessTracker />
247
- <AttendeesWidget user={user} event={poster} />
247
+ <AttendeesWidget user={user} event={poster} summit={summit} />
248
248
  <AdvertiseComponent section="event" column="right" />
249
249
  </div>
250
250
  </div>
@@ -59,7 +59,7 @@ const SponsorPageTemplate = ({ sponsorId, sponsors, scanBadge, eventId, lastData
59
59
  };
60
60
 
61
61
  if (notFound) {
62
- return <Interstitial title="Sponsor not found" navigateTo="/a/sponsors" ontained />
62
+ return <Interstitial title="Sponsor not found" navigateTo="/a/sponsors" contained />
63
63
  }
64
64
 
65
65
  const {
@@ -17,6 +17,7 @@ export const MARKETING_SETTINGS_KEYS = {
17
17
  regLiteInitialOrderComplete1stParagraph: "REG_LITE_INITIAL_ORDER_COMPLETE_STEP_1ST_PARAGRAPH",
18
18
  regLiteInitialOrderComplete2ndParagraph: "REG_LITE_INITIAL_ORDER_COMPLETE_STEP_2ND_PARAGRAPH",
19
19
  regLiteInitialOrderCompleteButton: "REG_LITE_INITIAL_ORDER_COMPLETE_BTN_LABEL",
20
+ regLiteOrderCompleteTitle: "REG_LITE_ORDER_COMPLETE_TITLE",
20
21
  regLiteOrderComplete1stParagraph: "REG_LITE_ORDER_COMPLETE_STEP_1ST_PARAGRAPH",
21
22
  regLiteOrderComplete2ndParagraph: "REG_LITE_ORDER_COMPLETE_STEP_2ND_PARAGRAPH",
22
23
  regLiteOrderCompleteButton: "REG_LITE_ORDER_COMPLETE_BTN_LABEL",
@@ -52,12 +52,12 @@ class SpeakerSynchStrategy extends AbstractSynchStrategy{
52
52
  }
53
53
 
54
54
  // check presentations
55
- if (entity && entity.hasOwnProperty('presentations')) {
56
- for (const publishedEventId of entity.presentations) {
55
+ if (entity && entity.hasOwnProperty('all_presentations')) {
56
+ for (const publishedEventId of entity.all_presentations) {
57
57
  const eventIdx = this.allIDXEvents.hasOwnProperty(publishedEventId) ? this.allIDXEvents[publishedEventId] : -1;
58
58
  let formerEntity = eventIdx === -1 ? null : ( (eventsData.length - 1) >= eventIdx ? eventsData[eventIdx] : null);
59
59
  if(formerEntity === null){
60
- console.log(`SpeakerSynchStrategy::process presentations activity ${publishedEventId} not found on data set`);
60
+ console.log(`SpeakerSynchStrategy::process all_presentations activity ${publishedEventId} not found on data set`);
61
61
  continue;
62
62
  }
63
63
  if (formerEntity && formerEntity.id !== publishedEventId) continue;
@@ -73,12 +73,12 @@ class SpeakerSynchStrategy extends AbstractSynchStrategy{
73
73
  }
74
74
 
75
75
  // check moderated presentations
76
- if(entity && entity.hasOwnProperty('moderated_presentations')){
77
- for (const publishedEventId of entity.moderated_presentations) {
76
+ if(entity && entity.hasOwnProperty('all_moderated_presentations')){
77
+ for (const publishedEventId of entity.all_moderated_presentations) {
78
78
  const eventIdx = this.allIDXEvents.hasOwnProperty(publishedEventId) ? this.allIDXEvents[publishedEventId] : -1;
79
79
  let formerEntity = eventIdx === -1 ? null : ( (eventsData.length - 1 ) >= eventIdx ? eventsData[eventIdx] : null);
80
80
  if(formerEntity === null) {
81
- console.log(`SpeakerSynchStrategy::process moderated_presentations activity ${publishedEventId} not found on data set`);
81
+ console.log(`SpeakerSynchStrategy::process all_moderated_presentations activity ${publishedEventId} not found on data set`);
82
82
  continue;
83
83
  }
84
84
  if (formerEntity && formerEntity.id !== publishedEventId) continue; // it's not the same
@@ -124,4 +124,4 @@ class SpeakerSynchStrategy extends AbstractSynchStrategy{
124
124
  }
125
125
  }
126
126
 
127
- export default SpeakerSynchStrategy;
127
+ export default SpeakerSynchStrategy;