@openeventkit/event-site 2.1.26 → 2.1.28

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.1.26",
4
+ "version": "2.1.28",
5
5
  "author": "Tipit LLC",
6
6
  "dependencies": {
7
7
  "@emotion/server": "^11.11.0",
@@ -87,7 +87,7 @@
87
87
  "markdown-it": "^12.0.0",
88
88
  "moment": "^2.27.0",
89
89
  "moment-timezone": "^0.5.31",
90
- "my-orders-tickets-widget": "1.0.0-beta.59",
90
+ "my-orders-tickets-widget": "1.0.0-beta.61",
91
91
  "object.assign": "^4.1.5",
92
92
  "openstack-uicore-foundation": "4.2.8",
93
93
  "path-browserify": "^1.0.1",
@@ -1,16 +1,12 @@
1
1
  import React, { useState, useEffect } from 'react';
2
2
  import { connect } from 'react-redux';
3
- import { generateCertificatePDF } from './CertificatePDF';
4
- import { useCertificateSettings } from '../utils/certificateSettings';
5
- import useMarketingSettings from '../utils/useMarketingSettings';
6
- import { MARKETING_SETTINGS_KEYS, DISPLAY_OPTIONS } from '../utils/useMarketingSettings';
7
- import useSiteSettings from '../utils/useSiteSettings';
8
- import styles from '../styles/full-profile.module.scss';
9
-
10
- const USER_ROLES = {
11
- SPEAKER: 'Speaker',
12
- ATTENDEE: 'Attendee'
13
- };
3
+ import { generatePDF } from './generatePDF';
4
+ import { useCertificateSettings } from './settings';
5
+ import useMarketingSettings from '../../utils/useMarketingSettings';
6
+ import { MARKETING_SETTINGS_KEYS, DISPLAY_OPTIONS } from '../../utils/useMarketingSettings';
7
+ import useSiteSettings from '../../utils/useSiteSettings';
8
+ import styles from '../../styles/full-profile.module.scss';
9
+ import { USER_ROLES } from './constants';
14
10
 
15
11
  const CertificateSection = ({
16
12
  user,
@@ -58,17 +54,15 @@ const CertificateSection = ({
58
54
  // Check if any ticket has speaker role
59
55
  const hasSpeakerTicket = allTickets.some(ticket => {
60
56
  // Check badge type name for speaker
61
- const badgeType = summit?.badge_types?.find(bt => bt.id === ticket.badge?.type_id);
57
+ const badgeType = ticket.badge?.type;
58
+
62
59
  if (badgeType?.name?.toLowerCase().includes('speaker')) {
63
60
  return true;
64
61
  }
65
62
 
66
- // Check badge features for speaker
67
- const featureIds = ticket.badge?.features || [];
68
- const badgeFeaturesTypes = summit?.badge_features_types || [];
63
+ const features = ticket.badge?.features || [];
69
64
 
70
- return featureIds.some(featureId => {
71
- const feature = badgeFeaturesTypes.find(f => f.id === featureId);
65
+ return features.some(feature => {
72
66
  return feature?.name?.toLowerCase().includes('speaker');
73
67
  });
74
68
  });
@@ -95,11 +89,10 @@ const CertificateSection = ({
95
89
  const summitData = {
96
90
  name: summit.name,
97
91
  logo: summit.logo,
98
- start_date: summit.start_date,
99
- end_date: summit.end_date
92
+ dates_label: summit.dates_label
100
93
  };
101
94
 
102
- await generateCertificatePDF(attendeeData, summitData, certificateSettings);
95
+ await generatePDF(attendeeData, summitData, certificateSettings);
103
96
  } catch (err) {
104
97
  console.error('Error downloading certificate:', err);
105
98
  setError('Failed to download certificate. Please try again.');
@@ -117,7 +110,11 @@ const CertificateSection = ({
117
110
  height: '5.5rem',
118
111
  color: 'var(--color_input_text_color)',
119
112
  backgroundColor: 'var(--color_input_background_color)',
120
- borderColor: 'var(--color_input_border_color)'
113
+ borderColor: 'var(--color_input_border_color)',
114
+ whiteSpace: 'normal',
115
+ wordBreak: 'break-word',
116
+ lineHeight: '1.2',
117
+ padding: '1rem'
121
118
  }}
122
119
  >
123
120
  Download Certificate of Attendance
@@ -0,0 +1,4 @@
1
+ export const USER_ROLES = {
2
+ SPEAKER: 'Speaker',
3
+ ATTENDEE: 'Attendee'
4
+ };
@@ -1,8 +1,9 @@
1
1
  import React from "react";
2
2
  import { Document, Page, Text, View, Image, StyleSheet, Font, pdf } from "@react-pdf/renderer";
3
3
 
4
- import fontRegular from "../../static/fonts/nunito-sans/nunito-sans-v18-latin-400.ttf";
5
- import fontBold from "../../static/fonts/nunito-sans/nunito-sans-v18-latin-700.ttf";
4
+ import fontRegular from "../../../static/fonts/nunito-sans/nunito-sans-v18-latin-400.ttf";
5
+ import fontBold from "../../../static/fonts/nunito-sans/nunito-sans-v18-latin-700.ttf";
6
+ import { USER_ROLES } from './constants';
6
7
 
7
8
  const registerDefaultFont = () => {
8
9
  try {
@@ -147,6 +148,7 @@ const CertificatePDF = ({
147
148
  logoUrl = null
148
149
  }) => {
149
150
  const role = attendee.role || "Attendee";
151
+ const isSpeaker = role === USER_ROLES.SPEAKER;
150
152
  const position = attendee.jobTitle || "";
151
153
  const company = attendee.company || "";
152
154
 
@@ -213,6 +215,7 @@ const CertificatePDF = ({
213
215
  textAlign: "center",
214
216
  letterSpacing: 0.15,
215
217
  lineHeight: "160%",
218
+ marginBottom: 5,
216
219
  },
217
220
  summitName: {
218
221
  fontSize: 24,
@@ -223,6 +226,15 @@ const CertificatePDF = ({
223
226
  letterSpacing: 0,
224
227
  lineHeight: "133%",
225
228
  },
229
+ summitDate: {
230
+ fontSize: 16,
231
+ fontWeight: "normal",
232
+ color: "#000000",
233
+ textAlign: "center",
234
+ letterSpacing: 0.15,
235
+ lineHeight: "150%",
236
+ marginTop: 8,
237
+ },
226
238
  name: {
227
239
  fontSize: nameFontSize,
228
240
  fontWeight: "normal",
@@ -275,7 +287,11 @@ const CertificatePDF = ({
275
287
 
276
288
  {/* Title */}
277
289
  <Text style={styles.title}>
278
- {settings.titleText || "CERTIFICATE OF ATTENDANCE"}
290
+ {isSpeaker && settings.speakerTitleText ?
291
+ settings.speakerTitleText :
292
+ !isSpeaker && settings.attendeeTitleText ?
293
+ settings.attendeeTitleText :
294
+ settings.titleText || (isSpeaker ? "CERTIFICATE OF APPRECIATION" : "CERTIFICATE OF ATTENDANCE")}
279
295
  </Text>
280
296
 
281
297
  {/* Event Name */}
@@ -283,6 +299,13 @@ const CertificatePDF = ({
283
299
  {settings.summitName || summit.name || "EVENT NAME"}
284
300
  </Text>
285
301
 
302
+ {/* Summit Date */}
303
+ {summit.dates_label && (
304
+ <Text style={styles.summitDate}>
305
+ {summit.dates_label}
306
+ </Text>
307
+ )}
308
+
286
309
  {/* Attendee Name */}
287
310
  <Text style={styles.name}>
288
311
  {fullName}
@@ -312,7 +335,7 @@ const CertificatePDF = ({
312
335
  };
313
336
 
314
337
  // helper function to generate and download the certificate
315
- export const generateCertificatePDF = async (attendee, summit, settings) => {
338
+ export const generatePDF = async (attendee, summit, settings) => {
316
339
  try {
317
340
  // Validate logo URL before generating PDF
318
341
  const logoUrlToValidate = settings.logo || summit.logo;
@@ -341,4 +364,3 @@ export const generateCertificatePDF = async (attendee, summit, settings) => {
341
364
  }
342
365
  };
343
366
 
344
- export default CertificatePDF;
@@ -0,0 +1,4 @@
1
+ export { default as DownloadButton } from './DownloadButton';
2
+ export { generatePDF } from './generatePDF';
3
+ export { useCertificateSettings } from './settings';
4
+ export { USER_ROLES } from './constants';
@@ -1,4 +1,4 @@
1
- import useMarketingSettings, { MARKETING_SETTINGS_KEYS, DISPLAY_OPTIONS } from './useMarketingSettings';
1
+ import useMarketingSettings, { MARKETING_SETTINGS_KEYS, DISPLAY_OPTIONS } from '../../utils/useMarketingSettings';
2
2
 
3
3
  export const useCertificateSettings = (siteFont = null) => {
4
4
  const { getSettingByKey } = useMarketingSettings();
@@ -20,6 +20,8 @@ export const useCertificateSettings = (siteFont = null) => {
20
20
  logoWidth: MARKETING_SETTINGS_KEYS.certificateLogoWidth,
21
21
  logoHeight: MARKETING_SETTINGS_KEYS.certificateLogoHeight,
22
22
  titleText: MARKETING_SETTINGS_KEYS.certificateTitleText,
23
+ attendeeTitleText: MARKETING_SETTINGS_KEYS.certificateAttendeeTitleText,
24
+ speakerTitleText: MARKETING_SETTINGS_KEYS.certificateSpeakerTitleText,
23
25
  summitName: MARKETING_SETTINGS_KEYS.certificateSummitName,
24
26
  showRole: MARKETING_SETTINGS_KEYS.certificateShowRole,
25
27
  };
@@ -21,7 +21,7 @@ const Seo = ({ title, description, location, children }) => {
21
21
  const { pathname } = location;
22
22
 
23
23
  const seo = {
24
- title: title ? `${siteTitle} - ${title}` : siteTitle,
24
+ title: title && siteTitle ? `${siteTitle} - ${title}` : (title || siteTitle || ''),
25
25
  description: description || defaultDescription,
26
26
  url: buildUrl(scheme, host, pathname),
27
27
  image: host && image ? buildUrl(scheme, host, image.publicURL) : null,
@@ -1,7 +1,6 @@
1
1
  import { reduceReducers } from '../utils/reducer-utils';
2
2
  import { LOGOUT_USER } from 'openstack-uicore-foundation/lib/security/actions';
3
3
  import {
4
-
5
4
  GET_DISQUS_SSO,
6
5
  GET_USER_PROFILE,
7
6
  START_LOADING_PROFILE,
@@ -65,7 +64,7 @@ const userReducer = (state = DEFAULT_STATE, action) => {
65
64
  const { response: userProfile } = payload;
66
65
  return {
67
66
  ...state,
68
- userProfile: userProfile,
67
+ userProfile: { ...userProfile, rsvp_invitations: [] },
69
68
  isAuthorized: isAuthorizedUser(userProfile.groups),
70
69
  hasTicket: userProfile.summit_tickets?.length > 0
71
70
  }
@@ -92,16 +91,18 @@ const userReducer = (state = DEFAULT_STATE, action) => {
92
91
  case REMOVE_FROM_SCHEDULE: {
93
92
  return { ...state, userProfile: { ...state.userProfile, schedule_summit_events: [...state.userProfile.schedule_summit_events.filter(ev => ev.id !== payload.id)] } }
94
93
  }
95
- case RSVP_CONFIRMED: {
96
- return { ...state, userProfile: { ...state.userProfile, rsvp: [...state.userProfile.rsvp, {...payload} ] } }
97
- }
98
- case RSVP_CANCELLED: {
99
- return { ...state, userProfile: {
100
- ...state.userProfile,
101
- rsvp: [...state?.userProfile?.rsvp?.filter(r => r.event_id !== payload.id)],
102
- rsvp_invitations:state?.userProfile?.rsvp_invitations?.filter(i => i.event_id !== payload.id),
103
- } }
94
+ case RSVP_CONFIRMED: {
95
+ return { ...state, userProfile: { ...state.userProfile, rsvp: [...state.userProfile.rsvp, { ...payload }] } }
96
+ }
97
+ case RSVP_CANCELLED: {
98
+ return {
99
+ ...state, userProfile: {
100
+ ...state.userProfile,
101
+ rsvp: [...state?.userProfile?.rsvp?.filter(r => r.event_id !== payload.id)],
102
+ rsvp_invitations: state?.userProfile?.rsvp_invitations?.filter(i => i.event_id !== payload.id),
103
+ }
104
104
  }
105
+ }
105
106
  case GET_DISQUS_SSO:
106
107
  const disqus = payload.response;
107
108
  return { ...state, loading: false, disqusSSO: disqus };
@@ -154,34 +155,37 @@ const userReducer = (state = DEFAULT_STATE, action) => {
154
155
  }
155
156
  case RSVP_INVITATION_ACCEPTED: {
156
157
  const invitation = payload.response;
157
- const userProfile = state.userProfile? {
158
- ...state?.userProfile,
159
- rsvp_invitations:[ ...state?.userProfile?.rsvp_invitations,{
160
- event_id: invitation.event_id,
161
- status: invitation.status,
162
- }],
163
- rsvp: [...state?.userProfile?.rsvp, {...invitation.rsvp}],
164
- schedule_summit_events: [...state?.userProfile?.schedule_summit_events, {id: invitation.event_id}]
158
+ const userProfile = state.userProfile ? {
159
+ ...state?.userProfile,
160
+ rsvp_invitations: [...state?.userProfile?.rsvp_invitations, {
161
+ event_id: invitation.event_id,
162
+ status: invitation.status,
163
+ }],
164
+ rsvp: [...state?.userProfile?.rsvp, { ...invitation.rsvp }],
165
+ schedule_summit_events: [...state?.userProfile?.schedule_summit_events, { id: invitation.event_id }]
165
166
  } : null;
166
167
 
167
- return { ...state,
168
- rsvpInvitation: invitation,
169
- // update invitations and rsvps
170
- userProfile: userProfile,
168
+ return {
169
+ ...state,
170
+ rsvpInvitation: invitation,
171
+ // update invitations and rsvps
172
+ userProfile: userProfile,
171
173
  }
172
174
  }
173
175
  case RSVP_INVITATION_REJECTED: {
174
- // update invitations
175
- const invitation = payload.response;
176
- const userProfile = state.userProfile ? {...state?.userProfile,
177
- rsvp_invitations:[ ...state?.userProfile?.rsvp_invitations,{
178
- event_id: invitation.event_id,
179
- status: invitation.status,
180
- }],
181
- }: null;
182
- return { ...state,
183
- rsvpInvitation: invitation,
184
- userProfile: userProfile,
176
+ // update invitations
177
+ const invitation = payload.response;
178
+ const userProfile = state.userProfile ? {
179
+ ...state?.userProfile,
180
+ rsvp_invitations: [...state?.userProfile?.rsvp_invitations, {
181
+ event_id: invitation.event_id,
182
+ status: invitation.status,
183
+ }],
184
+ } : null;
185
+ return {
186
+ ...state,
187
+ rsvpInvitation: invitation,
188
+ userProfile: userProfile,
185
189
  }
186
190
  }
187
191
  default:
@@ -17,7 +17,7 @@ import LiteScheduleComponent from '../components/LiteScheduleComponent'
17
17
  import AvatarEditorModal from '../components/AvatarEditorModal'
18
18
  import ChangePasswordComponent from '../components/ChangePasswordComponent';
19
19
  import AccessTracker from "../components/AttendeeToAttendeeWidgetComponent";
20
- import CertificateSection from '../components/CertificateSection';
20
+ import { DownloadButton as CertificateDownloadButton } from '../components/Certificates';
21
21
  import useMarketingSettings from '../utils/useMarketingSettings';
22
22
  import { MARKETING_SETTINGS_KEYS, DISPLAY_OPTIONS } from '../utils/useMarketingSettings';
23
23
  import { getAccessTokenSafely } from '../utils/loginUtils';
@@ -209,8 +209,8 @@ export const FullProfilePageTemplate = ({ user, getIDPProfile, updateProfile, up
209
209
 
210
210
  const params = new URLSearchParams({
211
211
  access_token: accessToken,
212
- fields: 'id,status',
213
- expand: 'owner'
212
+ fields: 'id,status,owner.summit_hall_checked_in,owner.first_name,owner.last_name,owner.company,owner.email,badge.type.name,badge.features.name',
213
+ expand: 'owner,badge,badge.type,badge.features'
214
214
  });
215
215
 
216
216
  const apiBaseUrl = getEnvVariable(SUMMIT_API_BASE_URL);
@@ -239,12 +239,11 @@ export const FullProfilePageTemplate = ({ user, getIDPProfile, updateProfile, up
239
239
  const certificatesEnabled = getSettingByKey(MARKETING_SETTINGS_KEYS.certificateEnabled) !== DISPLAY_OPTIONS.hide;
240
240
  const checkedInTickets = freshTickets.filter(ticket => {
241
241
  const isCheckedIn = ticket.owner?.summit_hall_checked_in === true;
242
- console.log(ticket)
243
242
  const isValidTicket = ticket.status === 'Paid';
244
243
  return isCheckedIn && isValidTicket;
245
244
  });
246
245
 
247
- const showCertificate = certificatesEnabled && checkedInTickets.length > 0;
246
+ const showCertificateDownload = certificatesEnabled && checkedInTickets.length > 0;
248
247
 
249
248
  const discardChanges = (state) => {
250
249
  switch (state) {
@@ -317,8 +316,8 @@ export const FullProfilePageTemplate = ({ user, getIDPProfile, updateProfile, up
317
316
  <h4>
318
317
  @{user.idpProfile?.nickname}
319
318
  </h4>
320
- {showCertificate && (
321
- <CertificateSection freshTickets={freshTickets} />
319
+ {showCertificateDownload && (
320
+ <CertificateDownloadButton freshTickets={freshTickets} />
322
321
  )}
323
322
  <ChangePasswordComponent updatePassword={handlePasswordUpdate} />
324
323
  </div>
@@ -8,6 +8,11 @@ class EventAPIRequest extends BaseAPIRequest {
8
8
  static instance;
9
9
 
10
10
  constructor() {
11
+ /*
12
+ * WARNING
13
+ * if any of these fields , relations or expand changes should be replicated here
14
+ * https://github.com/fntechgit/pub-api/blob/main/api/utils/summit_api_requests/event_api_request.py
15
+ */
11
16
  const primary_fields = [
12
17
  "id",
13
18
  "created",
@@ -79,8 +84,6 @@ class EventAPIRequest extends BaseAPIRequest {
79
84
 
80
85
  const locations_relations = ["location.venue", "location.floor", "location.venue.none", "location.floor.none"];
81
86
 
82
- // TODO: review relations for "current_attendance"
83
-
84
87
  const relations = [
85
88
  ...track_relations,
86
89
  ...type_relations,
@@ -3,7 +3,11 @@ class SpeakersAPIRequest extends BaseAPIRequest {
3
3
  static instance;
4
4
 
5
5
  constructor() {
6
-
6
+ /*
7
+ * WARNING
8
+ * if any of these fields , relations or expand changes should be replicated here
9
+ * https://github.com/fntechgit/pub-api/blob/main/api/utils/summit_api_requests/speaker_api_request.py
10
+ */
7
11
  const primary_fields =
8
12
  ['id', 'first_name', 'last_name', 'title', 'bio', 'member_id', 'pic', 'big_pic', 'company'];
9
13
 
@@ -3,16 +3,21 @@ const BaseAPIRequest = require("./BaseAPIRequest");
3
3
  class SummitAPIRequest extends BaseAPIRequest {
4
4
  static instance;
5
5
 
6
+
6
7
  constructor() {
8
+ /*
9
+ * WARNING
10
+ * if any of these fields , relations or expand changes should be replicated here
11
+ * https://github.com/fntechgit/pub-api/blob/main/api/utils/summit_api_requests/summit_api_request.py
12
+ */
7
13
  const primary_fields = [
8
14
  "id", "name", "start_date", "end_date", "time_zone_id", "time_zone_label", "secondary_logo", "slug",
9
- "support_email", "start_showing_venues_date", "dates_with_events", "logo",
15
+ "support_email", "start_showing_venues_date", "dates_with_events", "logo", "dates_label",
10
16
  "registration_allowed_refund_request_till_date", "allow_update_attendee_extra_questions", "is_virtual",
11
17
  "registration_disclaimer_mandatory", "registration_disclaimer_content", "reassign_ticket_till_date",
12
18
  "is_main", "title", "description", "time_zone"
13
19
  ];
14
20
 
15
- // TODO: to be reviewed later with data syncs actions to match the needs of the data update
16
21
  const event_types_fields = [
17
22
  "event_types.id"
18
23
  ];
@@ -37,9 +42,9 @@ class SummitAPIRequest extends BaseAPIRequest {
37
42
  ];
38
43
 
39
44
  const ticket_types_relations = ["ticket_types.none"];
40
- const tracks_relations = ["tracks", "tracks.subtracks.none"];
45
+ const tracks_relations = ["tracks", "tracks.subtracks", "tracks.subtracks.none"];
41
46
  const track_groups_relations = ["track_groups.none"];
42
- const location_relations = ["locations.none, locations.venue.none"];
47
+ const location_relations = ["locations.none", "locations.venue.none"];
43
48
  const event_types_relations = ["event_types.none"];
44
49
 
45
50
  const relations = [
@@ -68,6 +68,8 @@ export const MARKETING_SETTINGS_KEYS = {
68
68
  certificateLogoWidth: "CERTIFICATE_LOGO_WIDTH",
69
69
  certificateLogoHeight: "CERTIFICATE_LOGO_HEIGHT",
70
70
  certificateTitleText: "CERTIFICATE_TITLE_TEXT",
71
+ certificateAttendeeTitleText: "CERTIFICATE_ATTENDEE_TITLE_TEXT",
72
+ certificateSpeakerTitleText: "CERTIFICATE_SPEAKER_TITLE_TEXT",
71
73
  certificateSummitName: "CERTIFICATE_SUMMIT_NAME",
72
74
  certificateShowRole: "CERTIFICATE_SHOW_ROLE",
73
75
  }