@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 +4 -4
- package/src/actions/fetch-entities-actions.js +2 -1
- package/src/actions/update-data-actions.js +17 -1
- package/src/actions/user-actions.js +17 -5
- package/src/components/AttendeeToAttendeeWidgetComponent.js +12 -7
- package/src/components/AuthComponent.js +5 -2
- package/src/components/DisqusComponent.js +69 -94
- package/src/components/RegistrationLiteComponent.js +2 -0
- package/src/components/summit-my-orders-tickets/components/TicketPopup/TicketPopupEditDetailsForm/TicketPopupEditDetailsForm.js +173 -175
- package/src/components/summit-my-orders-tickets/components/TicketPopup/TicketPopupReassignForm.js +28 -5
- package/src/components/summit-my-orders-tickets/store/actions/ticket-actions.js +31 -15
- package/src/components/summit-my-orders-tickets/util/helpers/index.js +13 -0
- package/src/reducers/event-reducer.js +14 -1
- package/src/styles/style.scss +4 -0
- package/src/templates/event-page.js +2 -4
- package/src/templates/lobby-page.js +1 -1
- package/src/templates/marketing-page-template/MainColumn.js +1 -1
- package/src/templates/poster-detail-page.js +1 -1
- package/src/templates/sponsor-page.js +1 -1
- package/src/utils/useMarketingSettings.js +1 -0
- package/src/workers/sync_strategies/speaker_synch_strategy.js +7 -7
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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)
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
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
|
-
.
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
12
|
-
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
// Resize Handler
|
|
17
|
+
window.addEventListener('resize', onResize);
|
|
18
|
+
setIsMobile(window.innerWidth <= 768);
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
20
|
+
return () => {
|
|
21
|
+
window.removeEventListener('resize', onResize);
|
|
22
|
+
}
|
|
23
|
+
}, []);
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
// check Disqus SSO on every render
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
let disqusSsoInterval = null;
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
29
|
+
if (shortname) {
|
|
30
|
+
props.getDisqusSSO(shortname);
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
63
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
145
|
-
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
259
|
-
|
|
258
|
+
<div className="ticket-popup-edit-details-form">
|
|
259
|
+
{showSaveMessage &&
|
|
260
260
|
<CSSTransition
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
-
|
|
272
|
+
{showUnassignMessage &&
|
|
273
273
|
<CSSTransition
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
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
|
-
|
|
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
|
-
<
|
|
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.
|
|
332
|
-
{t("ticket_popup.
|
|
333
|
-
{!initialValues[TicketKeys.
|
|
358
|
+
<label htmlFor={TicketKeys.company}>
|
|
359
|
+
{t("ticket_popup.edit_company")}
|
|
360
|
+
{!initialValues[TicketKeys.company].name && <b> *</b>}
|
|
334
361
|
</label>
|
|
335
|
-
<
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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.
|
|
346
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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
|
-
|
|
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
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
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
|
-
|
|
434
|
+
<p className="error-label">{t("ticket_popup.edit_required")}</p>
|
|
437
435
|
}
|
|
438
436
|
</div>
|
|
439
|
-
|
|
440
|
-
|
|
437
|
+
}
|
|
438
|
+
</div>
|
|
441
439
|
|
|
442
|
-
|
|
440
|
+
{canSubmitChanges() &&
|
|
443
441
|
<div className="ticket-popup-footer">
|
|
444
442
|
<button
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
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
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
};
|
package/src/components/summit-my-orders-tickets/components/TicketPopup/TicketPopupReassignForm.js
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
242
|
-
|
|
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
|
-
|
|
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((
|
|
413
|
-
|
|
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
|
}
|
package/src/styles/style.scss
CHANGED
|
@@ -67,9 +67,7 @@ export const EventPageTemplate = class extends React.Component {
|
|
|
67
67
|
|
|
68
68
|
componentDidMount() {
|
|
69
69
|
const {eventId, event } = this.props;
|
|
70
|
-
|
|
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
|
|
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"
|
|
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('
|
|
56
|
-
for (const publishedEventId of entity.
|
|
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
|
|
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('
|
|
77
|
-
for (const publishedEventId of entity.
|
|
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
|
|
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;
|