@openeventkit/event-site 2.0.87 → 2.0.89

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/env.template CHANGED
@@ -31,4 +31,5 @@ GATSBY_SENTRY_RELEASE=
31
31
  GATSBY_METADATA_TITLE=
32
32
  GATSBY_METADATA_DESCRIPTION=
33
33
  GATSBY_CMS_BACKEND_REPO=
34
- GATSBY_CMS_BACKEND_BRANCH=
34
+ GATSBY_CMS_BACKEND_BRANCH=
35
+ GATSBY_SITE_URL=
package/gatsby-ssr.js CHANGED
@@ -1,4 +1,3 @@
1
- import * as React from "react";
2
1
  import ReduxWrapper from "./src/state/ReduxWrapper";
3
2
  import {
4
3
  HtmlAttributes,
@@ -31,6 +30,4 @@ global.window.matchMedia = () => ({
31
30
  addListener: () => {},
32
31
  removeListener: () => {}
33
32
  });
34
- global.window.window.requestAnimationFrame = () => {};
35
- global.window.window.cancelAnimationFrame = () => {};
36
33
  global.XMLHttpRequest = XMLHttpRequest;
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.87",
4
+ "version": "2.0.89",
5
5
  "author": "Tipit LLC",
6
6
  "dependencies": {
7
7
  "@mui/base": "^5.0.0-alpha.114",
@@ -29,6 +29,7 @@
29
29
  "browser-tabs-lock": "^1.2.15",
30
30
  "buffer": "^6.0.3",
31
31
  "bulma": "^0.9.0",
32
+ "chain-function": "^1.0.1",
32
33
  "classnames": "^2.3.1",
33
34
  "clean-html": "^1.5.0",
34
35
  "codemirror": "^5.55.0",
@@ -87,6 +88,7 @@
87
88
  "react-bootstrap": "^0.33.1",
88
89
  "react-datetime": "^2.16.3",
89
90
  "react-dnd": "15.1.1",
91
+ "react-dnd-html5-backend": "^16.0.1",
90
92
  "react-dom": "^18.2.0",
91
93
  "react-final-form": "6.5.9",
92
94
  "react-i18next": "^11.16.9",
@@ -120,7 +122,7 @@
120
122
  "stream-browserify": "^3.0.0",
121
123
  "stream-chat": "^2.7.2",
122
124
  "stream-chat-react": "3.1.7",
123
- "summit-registration-lite": "5.0.18",
125
+ "summit-registration-lite": "5.0.19",
124
126
  "superagent": "8.0.9",
125
127
  "sweetalert2": "^9.17.0",
126
128
  "upcoming-events-widget": "3.0.5",
@@ -50,6 +50,9 @@ export const UNCAST_PRESENTATION_VOTE_RESPONSE = 'UNCAST_PRESENTATION_VOTE_RESPO
50
50
  export const TOGGLE_PRESENTATION_VOTE = 'TOGGLE_PRESENTATION_VOTE';
51
51
  export const GET_EXTRA_QUESTIONS = 'GET_EXTRA_QUESTIONS';
52
52
  export const TICKET_OWNER_CHANGED = 'TICKET_OWNER_CHANGED';
53
+ export const REQUEST_INVITATION = 'REQUEST_INVITATION';
54
+ export const RECEIVE_INVITATION = 'RECEIVE_INVITATION';
55
+ export const REJECT_INVITATION = 'REJECT_INVITATION';
53
56
 
54
57
  // shortName is the unique identifier assigned to a Disqus site.
55
58
  export const getDisqusSSO = (shortName) => async (dispatch, getState) => {
@@ -436,7 +439,7 @@ export const updatePassword = (password) => async (dispatch) => {
436
439
 
437
440
  export const saveAttendeeQuestions = (values, ticketId = null) => async (dispatch, getState) => {
438
441
 
439
- const { userState: { userProfile: { summit_tickets } } } = getState();
442
+ const { userState: { userProfile: { summit_tickets } } } = getState();
440
443
 
441
444
  const normalizedEntity = {...values};
442
445
 
@@ -453,7 +456,7 @@ export const saveAttendeeQuestions = (values, ticketId = null) => async (dispatc
453
456
  } catch (e) {
454
457
  console.log('getAccessToken error: ', e);
455
458
  return Promise.reject();
456
- }
459
+ }
457
460
 
458
461
  let params = {
459
462
  access_token: accessToken,
@@ -529,10 +532,11 @@ export const setUserOrder = (order) => (dispatch) => Promise.resolve().then(() =
529
532
  export const checkOrderData = (order) => (dispatch, getState) => {
530
533
  if (!order) return;
531
534
 
532
- const { userState: { idpProfile: { company, given_name, family_name } } } = getState();
533
- const { owner_company, owner_first_name, owner_last_name } = order || {};
535
+ const { userState: { idpProfile: { company, given_name, family_name, email } } } = getState();
536
+ const { owner_company, owner_first_name, owner_last_name, owner_email } = order || {};
534
537
 
535
- if (owner_company !== company || owner_first_name !== given_name || owner_last_name !== family_name) {
538
+ // only change data if I am the order owner
539
+ if (owner_email === email && (owner_company !== company || owner_first_name !== given_name || owner_last_name !== family_name)) {
536
540
  const newProfile = {
537
541
  first_name: owner_first_name,
538
542
  last_name: owner_last_name,
@@ -577,3 +581,44 @@ export const doVirtualCheckIn = (attendee) => async (dispatch, getState) => {
577
581
  return e;
578
582
  });
579
583
  };
584
+
585
+
586
+ /**
587
+ * Get invitation by token to allow reject
588
+ * @param token
589
+ * @returns {function(*=, *): *}
590
+ */
591
+ export const getInvitation = (token) => async (dispatch) => {
592
+ dispatch(startLoading());
593
+
594
+ return getRequest(
595
+ createAction(REQUEST_INVITATION),
596
+ createAction(RECEIVE_INVITATION),
597
+ `${window.API_BASE_URL}/api/public/v1/summits/${window.SUMMIT_ID}/registration-invitations/${token}`,
598
+ customErrorHandler
599
+ )({})(dispatch)
600
+ .finally(() => dispatch(stopLoading()));
601
+ }
602
+
603
+ /**
604
+ * Reject invitation by token
605
+ * @param token
606
+ * @returns {function(*=, *): *}
607
+ */
608
+ export const rejectInvitation = (token) => async (dispatch) => {
609
+ dispatch(startLoading());
610
+
611
+ return deleteRequest(
612
+ null,
613
+ createAction(REJECT_INVITATION),
614
+ `${window.API_BASE_URL}/api/public/v1/summits/${window.SUMMIT_ID}/registration-invitations/${token}/reject`,
615
+ {},
616
+ customErrorHandler
617
+ )({})(dispatch)
618
+ .then(() => {
619
+ //redirect ?
620
+ })
621
+ .finally(() => dispatch(stopLoading()));
622
+ }
623
+
624
+
@@ -5,6 +5,7 @@ import {
5
5
  import marketingPage from "./marketingPage";
6
6
  import lobbyPage from "./lobbyPage";
7
7
  import expoHallPage from "./expoHallPage";
8
+ import invitationsRejectPage from "./invitationsRejectPage";
8
9
 
9
10
  const defaultPagesCollection = {
10
11
  ...collectionDefaults({
@@ -14,7 +15,8 @@ const defaultPagesCollection = {
14
15
  files: [
15
16
  marketingPage,
16
17
  lobbyPage,
17
- expoHallPage
18
+ expoHallPage,
19
+ invitationsRejectPage
18
20
  ]
19
21
  };
20
22
 
@@ -0,0 +1,45 @@
1
+ import {stringField} from "../../../fields";
2
+
3
+ import {
4
+ INVITATIONS_REJECT_PAGE_FILE_PATH
5
+ } from "@utils/filePath";
6
+
7
+ const invitationsRejectPage = {
8
+ label: "Invitations Reject Page",
9
+ name: "invitations-reject-page",
10
+ file: INVITATIONS_REJECT_PAGE_FILE_PATH,
11
+ fields: [
12
+ stringField({
13
+ label: "Title",
14
+ name: "title",
15
+ default: "Reject Invitation"
16
+ }),
17
+ stringField({
18
+ label: "Not found text",
19
+ name: "notFoundText",
20
+ required: false,
21
+ default: "Invitation not found."
22
+ }),
23
+ stringField({
24
+ label: "Rejected text",
25
+ name: "rejectedText",
26
+ required: false,
27
+ default: "Invitation has already been rejected."
28
+ }),
29
+ stringField({
30
+ label: "Reject text",
31
+ name: "rejectText",
32
+ required: false,
33
+ default: "To reject please click on the button below."
34
+ }),
35
+ stringField({
36
+ label: "Reject CTA label",
37
+ name: "rejectCTALabel",
38
+ required: false,
39
+ default: "Reject Invitation"
40
+ }),
41
+ ]
42
+ };
43
+
44
+ export default invitationsRejectPage;
45
+
@@ -0,0 +1,10 @@
1
+
2
+ module.exports = `
3
+ type InvitationsRejectPageJson implements Node {
4
+ title: String
5
+ notFoundText: String
6
+ rejectedText: String
7
+ rejectText: String
8
+ rejectCTALabel: String
9
+ }
10
+ `;
@@ -1,9 +1,11 @@
1
1
  const marketingPageTypeDefs = require("./marketingPage/typeDefs");
2
2
  const lobbyPageTypeDefs = require("./lobbyPage/typeDefs");
3
3
  const expoHallPageTypeDefs = require("./expoHallPage/typeDefs");
4
+ const invitationsRejectPageTypeDefs = require("./invitationsRejectPage/typeDefs");
4
5
 
5
6
  module.exports = [
6
7
  marketingPageTypeDefs,
7
8
  lobbyPageTypeDefs,
8
- expoHallPageTypeDefs
9
+ expoHallPageTypeDefs,
10
+ invitationsRejectPageTypeDefs
9
11
  ].join("");
@@ -138,7 +138,7 @@ const AuthComponent = ({
138
138
  allowsNativeAuth: allowsNativeAuth,
139
139
  allowsOtpAuth: allowsOtpAuth,
140
140
  initialEmailValue: initialEmailValue,
141
- title: 'Enter your email address to login with a one time code',
141
+ title: 'Sign in using the email associated with your account:',
142
142
  summitData: summit
143
143
  };
144
144
 
@@ -1,29 +1,34 @@
1
1
  import * as React from "react";
2
2
  import PropTypes from "prop-types";
3
+ import useSiteMetadata from "@utils/useSiteMetadata";
3
4
  import useSiteSettings from "@utils/useSiteSettings";
4
- import { Helmet } from "react-helmet";
5
5
  import { getSrc } from "gatsby-plugin-image";
6
- import { getUrl } from "@utils/urlFormating";
6
+ import { buildUrl } from "@utils/urlFormating";
7
+ import { getEnvVariable, SITE_URL } from "@utils/envVariables";
7
8
 
8
9
  const Seo = ({ title, description, location, children }) => {
9
10
  const {
10
- siteMetadata: {
11
- title: siteTitle,
12
- description: defaultDescription,
13
- image
14
- }
15
- } = useSiteSettings();
16
- const host = typeof window !== "undefined" ? window.location.host : null;
17
- const scheme = typeof window !== "undefined" ? window.location.protocol.replace(":", "") : "https";
11
+ title: siteTitle,
12
+ description: defaultDescription
13
+ } = useSiteMetadata();
14
+
15
+ const siteSettings = useSiteSettings();
16
+ const image = siteSettings.siteMetadata?.image
17
+
18
+ const siteUrl = getEnvVariable(SITE_URL);
19
+ const siteUrlInfo = siteUrl ? new URL(siteUrl) : null;
20
+ const scheme = siteUrlInfo ? siteUrlInfo.protocol.replace(":", "") : "https";
21
+ const host = siteUrlInfo ? siteUrlInfo.host : null;
18
22
  const { pathname } = location;
23
+
19
24
  const seo = {
20
25
  title: title ? `${siteTitle} - ${title}` : siteTitle,
21
26
  description: description || defaultDescription,
22
- url: getUrl(scheme, host, pathname),
23
- image: host && image ? getUrl(scheme, host, getSrc(image)) : null,
27
+ url: buildUrl(scheme, host, pathname),
28
+ image: host && image ? buildUrl(scheme, host, getSrc(image)) : null,
24
29
  };
25
30
  return (
26
- <Helmet>
31
+ <>
27
32
  {seo.title && <title>{seo.title}</title>}
28
33
  {seo.description && <meta name="description" content={seo.description} />}
29
34
  {seo.url && <meta property="og:url" content={seo.url} />}
@@ -38,7 +43,7 @@ const Seo = ({ title, description, location, children }) => {
38
43
  {seo.description && <meta name="twitter:description" content={seo.description} />}
39
44
  {seo.image && <meta name="twitter:image" content={seo.image} />}
40
45
  {children}
41
- </Helmet>
46
+ </>
42
47
  );
43
48
  };
44
49
 
@@ -0,0 +1,7 @@
1
+ {
2
+ "title": "Invitation rejection",
3
+ "notFoundText": "Invitation not found.",
4
+ "rejectedText": "You have rejected your invitation. ",
5
+ "rejectText": "Be certain. This is your last chance to purchase this ticket...",
6
+ "rejectCTALabel": "Reject"
7
+ }
@@ -4,6 +4,7 @@ import { connect } from "react-redux";
4
4
  import EventPage from "../../templates/event-page";
5
5
  import PostersPage from "../../templates/posters-page";
6
6
  import SchedulePage from "../../templates/schedule-page";
7
+ import InvitationsRejectPage from "../../templates/invitations-reject-page";
7
8
  import SponsorPage from "../../templates/sponsor-page";
8
9
  import ExpoHallPage from "../../templates/expo-hall-page";
9
10
  import FullProfilePage from "../../templates/full-profile-page";
@@ -19,8 +20,21 @@ import withFeedsWorker from "../../utils/withFeedsWorker";
19
20
  import Seo from "../../components/Seo";
20
21
  import Link from "../../components/Link";
21
22
  import { titleFromPathname } from "../../utils/urlFormating";
23
+ import {graphql} from "gatsby";
22
24
 
23
- const App = ({ isLoggedUser, user, summitPhase, allowClick = true }) => {
25
+ export const appQuery = graphql`
26
+ query {
27
+ invitationsRejectPageJson {
28
+ title
29
+ notFoundText
30
+ rejectedText
31
+ rejectText
32
+ rejectCTALabel
33
+ }
34
+ }
35
+ `;
36
+
37
+ const App = ({ isLoggedUser, user, summitPhase, allowClick = true, data }) => {
24
38
  return (
25
39
  <Location>
26
40
  {({ location }) => (
@@ -34,6 +48,7 @@ const App = ({ isLoggedUser, user, summitPhase, allowClick = true }) => {
34
48
  }}
35
49
  allowClick={allowClick}
36
50
  />
51
+ <InvitationsRejectPage path="/invitations/reject/:invitationToken" location={location} data={data} />
37
52
  <WithAuthRoute path="/" isLoggedIn={isLoggedUser} location={location}>
38
53
  <MyTicketsPage path="/my-tickets" isLoggedIn={isLoggedUser} user={user} location={location} />
39
54
  <FullProfilePage path="/profile" summitPhase={summitPhase} isLoggedIn={isLoggedUser} user={user} location={location} />
@@ -0,0 +1,25 @@
1
+ import { loggedUserReducer } from "openstack-uicore-foundation/lib/security/reducers";
2
+ import settingReducer from "./setting-reducer";
3
+ import userReducer from "./user-reducer";
4
+ import clockReducer from "./clock-reducer";
5
+ import summitReducer from "./summit-reducer";
6
+ import allSchedulesReducer from "./all-schedules-reducer";
7
+ import presentationsReducer from "./presentations-reducer";
8
+ import eventReducer from "./event-reducer";
9
+ import speakerReducer from "./speaker-reducer";
10
+ import sponsorReducer from "./sponsor-reducer";
11
+ import extraQuestionsReducer from "./extra-questions-reducer";
12
+
13
+ export {
14
+ loggedUserReducer,
15
+ settingReducer,
16
+ userReducer,
17
+ clockReducer,
18
+ summitReducer,
19
+ allSchedulesReducer,
20
+ presentationsReducer,
21
+ eventReducer,
22
+ speakerReducer,
23
+ sponsorReducer,
24
+ extraQuestionsReducer,
25
+ };
@@ -18,6 +18,7 @@ const INITIAL_STATE = {
18
18
  colorSource: 'track',
19
19
  is_my_schedule: false,
20
20
  only_events_with_attendee_access: false,
21
+ hide_past_events_with_show_always_on_schedule: false,
21
22
  };
22
23
 
23
24
  const scheduleReducer = (state = INITIAL_STATE, action) => {
@@ -41,6 +42,7 @@ const scheduleReducer = (state = INITIAL_STATE, action) => {
41
42
  filters,
42
43
  baseFilters,
43
44
  only_events_with_attendee_access,
45
+ hide_past_events_with_show_always_on_schedule,
44
46
  is_my_schedule,
45
47
  userProfile,
46
48
  isLoggedUser
@@ -48,15 +50,25 @@ const scheduleReducer = (state = INITIAL_STATE, action) => {
48
50
 
49
51
  const filterByAccessLevel = only_events_with_attendee_access && isLoggedUser;
50
52
  const filterByMySchedule = is_my_schedule && isLoggedUser;
51
- const allFilteredEvents = preFilterEvents(all_events, pre_filters, summitTimeZoneId, userProfile, filterByAccessLevel, filterByMySchedule);
53
+ const allFilteredEvents = preFilterEvents(all_events, pre_filters, summitTimeZoneId, userProfile, filterByAccessLevel, filterByMySchedule, hide_past_events_with_show_always_on_schedule);
52
54
  const newFilters = syncFilters(filters, state.filters);
53
- const events = getFilteredEvents(allFilteredEvents, newFilters, summitTimeZoneId);
55
+ const events = getFilteredEvents(allFilteredEvents, newFilters, summitTimeZoneId, hide_past_events_with_show_always_on_schedule);
54
56
 
55
- return {...state, allEvents: allFilteredEvents, baseFilters, filters: newFilters, colorSource: color_source.toLowerCase(), events, is_my_schedule, only_events_with_attendee_access};
57
+ return {
58
+ ...state,
59
+ allEvents: allFilteredEvents,
60
+ baseFilters,
61
+ filters: newFilters,
62
+ colorSource: color_source.toLowerCase(),
63
+ events,
64
+ is_my_schedule,
65
+ only_events_with_attendee_access,
66
+ hide_past_events_with_show_always_on_schedule
67
+ };
56
68
  }
57
69
  case `SCHED_UPDATE_FILTER`: {
58
70
 
59
- const { type : filterType, values } = payload;
71
+ const { type : filterType, values, hide_past_events_with_show_always_on_schedule } = payload;
60
72
  const { filters, allEvents } = state;
61
73
  // update the filters with new values
62
74
  const newFilters = {
@@ -70,24 +82,24 @@ const scheduleReducer = (state = INITIAL_STATE, action) => {
70
82
  return {...state,
71
83
  filters : newFilters ,
72
84
  // refilter events
73
- events: getFilteredEvents(allEvents, newFilters, summitTimeZoneId)}
85
+ events: getFilteredEvents(allEvents, newFilters, summitTimeZoneId, hide_past_events_with_show_always_on_schedule)}
74
86
  }
75
87
  case `SCHED_UPDATE_FILTERS`: {
76
88
  const {filters, view} = payload;
77
- const {allEvents} = state;
89
+ const {allEvents, hide_past_events_with_show_always_on_schedule} = state;
78
90
 
79
91
  // update events
80
- const events = getFilteredEvents(allEvents, filters, summitTimeZoneId);
92
+ const events = getFilteredEvents(allEvents, filters, summitTimeZoneId, hide_past_events_with_show_always_on_schedule);
81
93
 
82
94
  return {...state, filters, events, view}
83
95
  }
84
96
  case `SCHED_CLEAR_FILTERS`: {
85
- const { allEvents, baseFilters } = state;
97
+ const { allEvents, baseFilters, hide_past_events_with_show_always_on_schedule } = state;
86
98
 
87
99
  return {...state,
88
100
  filters : baseFilters ,
89
101
  // refilter events
90
- events: getFilteredEvents(allEvents, baseFilters, summitTimeZoneId)}
102
+ events: getFilteredEvents(allEvents, baseFilters, summitTimeZoneId, hide_past_events_with_show_always_on_schedule)}
91
103
  }
92
104
  case `SCHED_CHANGE_VIEW`: {
93
105
  const {view} = payload;
@@ -99,20 +111,20 @@ const scheduleReducer = (state = INITIAL_STATE, action) => {
99
111
  }
100
112
  case `SCHED_ADD_TO_SCHEDULE`: {
101
113
  const event = payload;
102
- const {allEvents, filters} = state;
114
+ const {allEvents, filters, hide_past_events_with_show_always_on_schedule} = state;
103
115
 
104
116
  allEvents.push(event);
105
- const events = getFilteredEvents(allEvents, filters, summitTimeZoneId);
117
+ const events = getFilteredEvents(allEvents, filters, summitTimeZoneId, hide_past_events_with_show_always_on_schedule);
106
118
 
107
119
  return {...state, allEvents, events};
108
120
 
109
121
  }
110
122
  case `SCHED_REMOVE_FROM_SCHEDULE`: {
111
123
  const event = payload;
112
- const {allEvents: allEventsCurrent, filters} = state;
124
+ const {allEvents: allEventsCurrent, filters, hide_past_events_with_show_always_on_schedule} = state;
113
125
 
114
126
  const allEvents = allEventsCurrent.filter(ev => ev.id !== event.id);
115
- const events = getFilteredEvents(allEvents, filters, summitTimeZoneId);
127
+ const events = getFilteredEvents(allEvents, filters, summitTimeZoneId, hide_past_events_with_show_always_on_schedule);
116
128
 
117
129
  return {...state, allEvents, events};
118
130
 
@@ -16,7 +16,10 @@ import {
16
16
  CAST_PRESENTATION_VOTE_RESPONSE,
17
17
  UNCAST_PRESENTATION_VOTE_RESPONSE,
18
18
  TOGGLE_PRESENTATION_VOTE,
19
- TICKET_OWNER_CHANGED
19
+ TICKET_OWNER_CHANGED,
20
+ RECEIVE_INVITATION,
21
+ REQUEST_INVITATION,
22
+ REJECT_INVITATION
20
23
  } from '../actions/user-actions';
21
24
  import { RESET_STATE } from '../actions/base-actions-definitions';
22
25
  import { isAuthorizedUser } from '../utils/authorizedGroups';
@@ -29,7 +32,8 @@ const DEFAULT_STATE = {
29
32
  idpProfile: null,
30
33
  isAuthorized: false,
31
34
  hasTicket: false,
32
- attendee: null
35
+ attendee: null,
36
+ invitation: null,
33
37
  }
34
38
 
35
39
  const userReducer = (state = DEFAULT_STATE, action) => {
@@ -107,6 +111,15 @@ const userReducer = (state = DEFAULT_STATE, action) => {
107
111
  }
108
112
  };
109
113
  }
114
+ case REQUEST_INVITATION: {
115
+ return {...state, invitation: null};
116
+ }
117
+ case RECEIVE_INVITATION: {
118
+ return {...state, invitation: payload.response}
119
+ }
120
+ case REJECT_INVITATION: {
121
+ return {...state, invitation: {...state.invitation, status: 'Rejected'}}
122
+ }
110
123
  default:
111
124
  return state;
112
125
  }
@@ -1,31 +1,21 @@
1
- import React from "react";
2
- import {connect} from "react-redux";
3
- import {navigate} from "gatsby";
1
+ import * as React from "react";
2
+ import { navigate } from "gatsby";
4
3
 
5
4
  /**
6
- *
7
- * @param isLoggedIn
8
- * @param location
9
- * @param children
10
- * @returns {null|*}
11
- * @constructor
5
+ * @param {boolean} isLoggedIn - Indicates whether the user is logged in.
6
+ * @param {object} location - The location object from React Router.
7
+ * @param {ReactNode} children - The children components to be rendered.
8
+ * @returns {ReactNode|null} - Returns children if isLoggedIn is true, otherwise redirects to login.
12
9
  */
13
- const WithAuthRoute = ({
14
-
15
- isLoggedIn,
16
- location,
17
- children
18
- }) => {
19
-
10
+ const WithAuthRoute = ({ isLoggedIn, location, children }) => {
11
+ React.useEffect(() => {
20
12
  if (!isLoggedIn) {
21
- // reject it and redirect with current location to login
22
- navigate("/#login=1", {state: {backUrl: `${location.pathname}`,},});
23
- return null;
13
+ // Use navigate with state to redirect and add data to navigation state
14
+ navigate("/#login=1", { state: { backUrl: `${location.pathname}` } });
24
15
  }
16
+ }, [isLoggedIn, location.pathname]);
25
17
 
26
- return children;
18
+ return isLoggedIn ? children : null;
27
19
  };
28
20
 
29
- const mapStateToProps = ({}) => ({});
30
-
31
- export default connect(mapStateToProps, {})(WithAuthRoute);
21
+ export default WithAuthRoute;
@@ -1,23 +1,24 @@
1
- import React from "react";
1
+ import * as React from "react";
2
2
  import { Provider } from "react-redux";
3
3
  import { PersistGate } from "redux-persist/integration/react";
4
- import store, { persistor } from "./store";
5
-
4
+ import { store, persistor } from "./store";
6
5
  import { RESET_STATE } from "../actions/base-actions-definitions";
7
6
 
8
7
  const onBeforeLift = () => {
9
- const params = new URLSearchParams(window.location.search);
10
- const flush = params.has("flushState");
8
+ const params = new URLSearchParams(window.location.search);
9
+ const flush = params.has("flushState");
11
10
 
12
- if (flush) {
13
- store.dispatch({ type: RESET_STATE, payload: null });
14
- }
11
+ if (flush) {
12
+ store.dispatch({ type: RESET_STATE, payload: null });
13
+ }
15
14
  };
16
15
 
17
- export default ({ element }) => (
18
- <Provider store={store}>
19
- <PersistGate onBeforeLift={onBeforeLift} persistor={persistor}>
20
- {element}
21
- </PersistGate>
22
- </Provider>
16
+ const ReduxWrapper = ({ element }) => (
17
+ <Provider store={store}>
18
+ <PersistGate onBeforeLift={onBeforeLift} persistor={persistor}>
19
+ {() => element}
20
+ </PersistGate>
21
+ </Provider>
23
22
  );
23
+
24
+ export default ReduxWrapper;
@@ -1,68 +1,62 @@
1
1
  import { applyMiddleware, compose, createStore } from "redux";
2
2
  import { persistCombineReducers, persistStore } from "redux-persist";
3
+ import storage from "redux-persist/lib/storage";
3
4
  import thunk from "redux-thunk";
4
- import storage from "./reduxPersistStorage";
5
5
 
6
- import { loggedUserReducer } from "openstack-uicore-foundation/lib/security/reducers";
7
- import settingReducer from "../reducers/setting-reducer";
8
- import userReducer from "../reducers/user-reducer";
9
- import clockReducer from "../reducers/clock-reducer";
10
- import summitReducer from "../reducers/summit-reducer";
11
- import allSchedulesReducer from "../reducers/all-schedules-reducer";
12
- import presentationsReducer from "../reducers/presentations-reducer";
13
- import eventReducer from "../reducers/event-reducer";
14
- import speakerReducer from "../reducers/speaker-reducer";
15
- import sponsorReducer from "../reducers/sponsor-reducer";
16
- import extraQuestionReducer from "../reducers/extra-questions-reducer";
6
+ import * as reducers from "../reducers";
17
7
 
18
- // get from process.env bc window is not set yet
8
+ // Get from process.env because window is not set yet
19
9
  const clientId = process.env.GATSBY_OAUTH2_CLIENT_ID;
20
10
  const summitID = process.env.GATSBY_SUMMIT_ID;
21
11
 
22
12
  const config = {
23
13
  key: `root_${clientId}_${summitID}`,
24
- storage: storage,
14
+ storage,
25
15
  blacklist: [
26
16
  // this will be not saved to persistent storage see
27
17
  // https://github.com/rt2zz/redux-persist#blacklist--whitelist
28
- 'summitState',
29
- 'allSchedulesState',
30
- 'presentationsState',
31
- 'eventState',
32
- 'speakerState',
33
- 'sponsorState',
34
- ]
18
+ "summitState",
19
+ "allSchedulesState",
20
+ "presentationsState",
21
+ "eventState",
22
+ "speakerState",
23
+ "sponsorState",
24
+ ],
35
25
  };
36
26
 
37
- const persistedReducers = persistCombineReducers(config, {
38
- loggedUserState: loggedUserReducer,
39
- settingState: settingReducer,
40
- userState: userReducer,
41
- allSchedulesState: allSchedulesReducer,
42
- clockState: clockReducer,
43
- eventState: eventReducer,
44
- presentationsState: presentationsReducer,
45
- summitState: summitReducer,
46
- speakerState: speakerReducer,
47
- sponsorState: sponsorReducer,
48
- extraQuestionState: extraQuestionReducer
49
- });
27
+ const states = {
28
+ loggedUserState: reducers.loggedUserReducer,
29
+ settingState: reducers.settingReducer,
30
+ userState: reducers.userReducer,
31
+ clockState: reducers.clockReducer,
32
+ summitState: reducers.summitReducer,
33
+ allSchedulesState: reducers.allSchedulesReducer,
34
+ presentationsState: reducers.presentationsReducer,
35
+ eventState: reducers.eventReducer,
36
+ speakerState: reducers.speakerReducer,
37
+ sponsorState: reducers.sponsorReducer,
38
+ extraQuestionsReducer: reducers.extraQuestionsReducer
39
+ };
50
40
 
51
- function appendLoggedUser({ getState }) {
52
- return next => action => {
53
- const { userState: { userProfile } } = getState();
54
- // Call the next dispatch method in the middleware chain.
55
- action.userProfile = userProfile;
56
- return next(action);
57
- }
58
- }
41
+ const appendLoggedUser = ({ getState }) => (next) => (action) => {
42
+ const { userState: { userProfile } } = getState();
43
+ action.userProfile = userProfile;
44
+ return next(action);
45
+ };
59
46
 
60
- const composeEnhancers = typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose;
47
+ const composeEnhancers = typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
48
+ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
49
+ : compose;
61
50
 
62
- const store = createStore(persistedReducers, composeEnhancers(applyMiddleware(appendLoggedUser, thunk)));
51
+ const enhancer = composeEnhancers(applyMiddleware(appendLoggedUser, thunk));
63
52
 
64
- const onRehydrateComplete = () => {};
53
+ // Create store with persistor
54
+ export const { store, persistor } = (() => {
55
+ const persistedReducers = persistCombineReducers(config, states);
65
56
 
66
- export const persistor = persistStore(store, null, onRehydrateComplete);
57
+ const store = createStore(persistedReducers, enhancer);
58
+ const onRehydrateComplete = () => {};
59
+ const persistor = persistStore(store, null, onRehydrateComplete);
67
60
 
68
- export default store;
61
+ return { store, persistor };
62
+ })();
@@ -0,0 +1,24 @@
1
+ @import "colors.scss";
2
+
3
+ .container {
4
+ position: inherit;
5
+
6
+ .wrapper {
7
+ display: flex;
8
+ flex-direction: column;
9
+ max-width: 800px;
10
+ margin: 0 auto;
11
+
12
+ h1 {
13
+ margin-top: 40px;
14
+ }
15
+
16
+ div {
17
+ margin-top: 10px;
18
+ }
19
+
20
+ button {
21
+ margin-top: 40px;
22
+ }
23
+ }
24
+ }
@@ -13,6 +13,7 @@ const ExpoHallPage = ({
13
13
  }) => {
14
14
  const { expoHallPageJson: { hero } } = data;
15
15
  const style = hero?.background ? { backgroundImage: `url(${getSrc(hero.background.src)})` } : {};
16
+
16
17
  return (
17
18
  <Layout location={location}>
18
19
  <AttendanceTrackerComponent />
@@ -0,0 +1,106 @@
1
+ import React, {useEffect, useState, useCallback, useRef} from "react";
2
+ import PropTypes from "prop-types";
3
+ import {connect} from "react-redux";
4
+ import Layout from "../components/Layout";
5
+ import AttendanceTrackerComponent from "../components/AttendanceTrackerComponent";
6
+ import AccessTracker from "../components/AttendeeToAttendeeWidgetComponent";
7
+ import {getInvitation, rejectInvitation} from "../actions/user-actions";
8
+
9
+ import styles from "../styles/invitation-reject.module.scss";
10
+
11
+ const InvitationsRejectPage = ({data, location, invitationToken, invitation, loading, ...props}) => {
12
+ const [loaded, setLoaded] = useState(false);
13
+ const [rejecting, setRejecting] = useState(false);
14
+ const {invitationsRejectPageJson: {title, notFoundText, rejectedText, rejectText, rejectCTALabel}} = data;
15
+ const titleStr = title || "Reject invitation"
16
+ const rejectStr = rejectText || "To reject please click on the button below."
17
+ const rejectCTA = rejectCTALabel || "Reject"
18
+ const notFoundStr = notFoundText || "Invitation not found."
19
+ const rejectedStr = rejectedText || "Invitation has already been rejected."
20
+
21
+ useEffect(() => {
22
+ setLoaded(false);
23
+ if (invitationToken) {
24
+ props.getInvitation(invitationToken)
25
+ .finally(() => {
26
+ setLoaded(true)
27
+ });
28
+ }
29
+ }, []);
30
+
31
+ const rejectInvitation = () => {
32
+ setRejecting(true);
33
+ props.rejectInvitation(invitationToken)
34
+ .finally(() => {
35
+ setRejecting(false);
36
+ });
37
+ }
38
+
39
+ const getMessage = () => {
40
+ if (!invitationToken) {
41
+ return (
42
+ <>
43
+ <div>Missing token.</div>
44
+ </>
45
+ );
46
+ }
47
+ else if (loaded) {
48
+ if (!invitation) {
49
+ return (
50
+ <>
51
+ <div>{notFoundStr}</div>
52
+ </>
53
+ );
54
+ } else {
55
+ if (invitation.status === 'Rejected') {
56
+ return (
57
+ <>
58
+ <div>{rejectedStr}</div>
59
+ </>
60
+ )
61
+ } else {
62
+ return (
63
+ <>
64
+ <div>{rejectStr}</div>
65
+ <button className="button is-large" onClick={rejectInvitation} disabled={rejecting}>
66
+ {rejectCTA}
67
+ </button>
68
+ </>
69
+ )
70
+ }
71
+
72
+ }
73
+ } else {
74
+ return null;
75
+ }
76
+ }
77
+
78
+
79
+ return (
80
+ <Layout location={location}>
81
+ <div className={`container ${styles.container}`}>
82
+ <div className={styles.wrapper}>
83
+ <h1>{titleStr}</h1>
84
+ {getMessage()}
85
+ </div>
86
+ </div>
87
+ <AttendanceTrackerComponent/>
88
+ <AccessTracker/>
89
+ </Layout>
90
+ );
91
+ };
92
+
93
+ InvitationsRejectPage.propTypes = {
94
+ invitationToken: PropTypes.string.isRequired
95
+ };
96
+
97
+ const mapStateToProps = ({userState, globalState}) => ({
98
+ invitation: userState.invitation,
99
+ loading: globalState?.loading
100
+ });
101
+
102
+ export default connect(
103
+ mapStateToProps, {
104
+ getInvitation,
105
+ rejectInvitation
106
+ })(InvitationsRejectPage);
@@ -1,16 +1,17 @@
1
- import React from 'react'
2
- import {connect} from "react-redux";
3
- import PropTypes from 'prop-types'
4
- import {navigate} from 'gatsby'
5
- import {getEnvVariable, REGISTRATION_BASE_URL} from '../utils/envVariables'
6
- import HeroComponent from '../components/HeroComponent'
1
+ import * as React from "react";
2
+ import { connect } from "react-redux";
3
+ import PropTypes from "prop-types";
4
+ import { Redirect } from "@gatsbyjs/reach-router";
5
+ import { getEnvVariable, REGISTRATION_BASE_URL } from "../utils/envVariables";
6
+ import HeroComponent from "../components/HeroComponent";
7
+ import { navigate } from "gatsby";
7
8
 
8
9
  export const TicketErrorPageTemplate = class extends React.Component {
9
10
 
10
11
  constructor(props) {
11
12
  super(props);
12
13
 
13
- const {location} = this.props;
14
+ const { location } = this.props;
14
15
 
15
16
  this.state = {
16
17
  error: location.state?.error
@@ -18,21 +19,21 @@ export const TicketErrorPageTemplate = class extends React.Component {
18
19
  }
19
20
 
20
21
  redirect() {
21
- const {error} = this.state;
22
+ const { error } = this.state;
22
23
 
23
24
  if (getEnvVariable(REGISTRATION_BASE_URL)) {
24
25
 
25
26
  let targetUrl = null;
26
27
 
27
28
  switch (error) {
28
- case 'no-virtual-access':
29
- targetUrl = `/`;
29
+ case "no-virtual-access":
30
+ targetUrl = "/";
30
31
  break
31
- case 'no-ticket':
32
- targetUrl = `/#registration=1`;
32
+ case "no-ticket":
33
+ targetUrl = "/#registration=1";
33
34
  break;
34
- case 'incomplete':
35
- targetUrl = `/a/extra-questions`;
35
+ case "incomplete":
36
+ targetUrl = "/a/extra-questions";
36
37
  break;
37
38
  default:
38
39
  break;
@@ -46,25 +47,23 @@ export const TicketErrorPageTemplate = class extends React.Component {
46
47
  return;
47
48
  }
48
49
 
49
- setTimeout(() => {
50
- navigate('/')
51
- }, 5000);
50
+ setTimeout(() => navigate("/"), 5000);
52
51
  }
53
52
 
54
53
  getErrorMessage() {
55
- const {error} = this.state;
54
+ const { error } = this.state;
56
55
 
57
- let message = '';
56
+ let message = "";
58
57
 
59
58
  switch (error) {
60
- case 'no-virtual-access':
61
- message = 'I’m sorry your badge does not allow access to this section.';
59
+ case "no-virtual-access":
60
+ message = "I’m sorry your badge does not allow access to this section.";
62
61
  break;
63
- case 'no-ticket':
64
- message = 'I’m sorry you are not registered for this event.';
62
+ case "no-ticket":
63
+ message = "I’m sorry you are not registered for this event.";
65
64
  break;
66
- case 'incomplete':
67
- message = 'You have not answered questions required to join the event.';
65
+ case "incomplete":
66
+ message = "You have not answered questions required to join the event.";
68
67
  break;
69
68
  default:
70
69
  break;
@@ -74,11 +73,13 @@ export const TicketErrorPageTemplate = class extends React.Component {
74
73
  }
75
74
 
76
75
  getRedirectMessage() {
77
- const {error} = this.state;
78
- let message = '';
76
+ const { error } = this.state;
77
+
78
+ let message = "";
79
+
79
80
  switch (error) {
80
- case 'no-ticket':
81
- message = getEnvVariable(REGISTRATION_BASE_URL) ? 'You will be redirected to registration.' : '';
81
+ case "no-ticket":
82
+ message = getEnvVariable(REGISTRATION_BASE_URL) ? "You will be redirected to registration." : "";
82
83
  break;
83
84
  default:
84
85
  break;
@@ -88,7 +89,7 @@ export const TicketErrorPageTemplate = class extends React.Component {
88
89
  }
89
90
 
90
91
  render() {
91
- const {error} = this.state;
92
+ const { error } = this.state;
92
93
 
93
94
  if (error) {
94
95
  this.redirect();
@@ -100,8 +101,7 @@ export const TicketErrorPageTemplate = class extends React.Component {
100
101
  )
101
102
  }
102
103
 
103
- navigate('/');
104
- return null
104
+ return <Redirect to={"/"} noThrow />;
105
105
  }
106
106
  };
107
107
 
@@ -109,23 +109,19 @@ TicketErrorPageTemplate.propTypes = {
109
109
  location: PropTypes.object,
110
110
  };
111
111
 
112
- const TicketErrorPage = ({location, summit}) => {
113
-
114
- return (
115
- <TicketErrorPageTemplate
116
- location={location}
117
- summit={summit}
118
- />
119
- )
120
-
121
- };
112
+ const TicketErrorPage = ({ location, summit }) => (
113
+ <TicketErrorPageTemplate
114
+ location={location}
115
+ summit={summit}
116
+ />
117
+ );
122
118
 
123
119
  TicketErrorPage.propTypes = {
124
120
  location: PropTypes.object,
125
121
  };
126
122
 
127
- const mapStateToProps = ({summitState}) => ({
123
+ const mapStateToProps = ({ summitState }) => ({
128
124
  summit: summitState.summit,
129
125
  });
130
126
 
131
- export default connect(mapStateToProps, {})(TicketErrorPage);
127
+ export default connect(mapStateToProps, null)(TicketErrorPage);
@@ -1,3 +1,4 @@
1
+ export const SITE_URL = 'SITE_URL';
1
2
  export const IDP_BASE_URL = 'IDP_BASE_URL';
2
3
  export const SUMMIT_API_BASE_URL = 'SUMMIT_API_BASE_URL';
3
4
  export const SUMMIT_ID = 'SUMMIT_ID';
@@ -26,6 +27,15 @@ export const TIMEINTERVALSINCE1970_API_URL = 'TIMEINTERVALSINCE1970_API_URL';
26
27
  export const ABLY_API_KEY = 'ABLY_API_KEY';
27
28
 
28
29
  const processEnv = {
30
+ /**
31
+ * Retrieve the site URL from environment variable set by the deploy provider.
32
+ * See documentation for more details:
33
+ * - Netlify: {@link https://docs.netlify.com/configure-builds/environment-variables/#deploy-urls-and-metadata}
34
+ * - Cloudflare Pages: {@link https://developers.cloudflare.com/pages/platform/build-configuration#environment-variables}
35
+ *
36
+ * If not available, fallback to user-defined GATSBY_SITE_URL env var.
37
+ */
38
+ SITE_URL: process.env.GATSBY_URL || process.env.GATSBY_CF_PAGES_URL || process.env.GATSBY_SITE_URL,
29
39
  IDP_BASE_URL: process.env.GATSBY_IDP_BASE_URL,
30
40
  SUMMIT_API_BASE_URL: process.env.GATSBY_SUMMIT_API_BASE_URL,
31
41
  API_BASE_URL: process.env.GATSBY_SUMMIT_API_BASE_URL,
@@ -62,6 +72,7 @@ export const getEnvVariable = (name) => {
62
72
  }
63
73
 
64
74
  if (typeof window === 'object') {
75
+ window.SITE_URL = processEnv[SITE_URL];
65
76
  window.OAUTH2_FLOW = processEnv[OAUTH2_FLOW];
66
77
  window.OAUTH2_CLIENT_ID = processEnv[OAUTH2_CLIENT_ID];
67
78
  window.SCOPES = processEnv[SCOPES];
@@ -35,6 +35,7 @@ const POSTERS_PAGES_FILE_PATH = `${STATIC_CONTENT_DIR_PATH}/posters-pages.json`;
35
35
  const MARKETING_SETTINGS_FILE_PATH = `${DATA_DIR_PATH}/marketing-settings.json`;
36
36
  const MAINTENANCE_FILE_PATH = `${STATIC_CONTENT_DIR_PATH}/maintenance.json`;
37
37
  const EXPO_HALL_PAGE_FILE_PATH = `${STATIC_CONTENT_DIR_PATH}/expo-hall-page/index.json`;
38
+ const INVITATIONS_REJECT_PAGE_FILE_PATH = `${STATIC_CONTENT_DIR_PATH}/invitations-reject-page/index.json`;
38
39
  const SPONSORS_FILE_NAME = "sponsors.json";
39
40
  const SPONSORS_FILE_PATH = `${STATIC_CONTENT_DIR_PATH}/${SPONSORS_FILE_NAME}`;
40
41
  const CMS_FONT_FILE_PATH = "/static/fonts/"
@@ -50,6 +51,7 @@ exports.REQUIRED_DIR_PATHS = [
50
51
  SITE_SETTINGS_DIR_PATH,
51
52
  MARKETING_PAGE_DIR_PATH,
52
53
  LOBBY_PAGE_DIR_PATH,
54
+ INVITATIONS_REJECT_PAGE_FILE_PATH,
53
55
  NAVBAR_DIR_PATH,
54
56
  FOOTER_DIR_PATH
55
57
  ];
@@ -83,6 +85,7 @@ exports.POSTERS_PAGES_FILE_PATH = POSTERS_PAGES_FILE_PATH;
83
85
  exports.MARKETING_SETTINGS_FILE_PATH = MARKETING_SETTINGS_FILE_PATH;
84
86
  exports.MAINTENANCE_FILE_PATH = MAINTENANCE_FILE_PATH;
85
87
  exports.EXPO_HALL_PAGE_FILE_PATH = EXPO_HALL_PAGE_FILE_PATH;
88
+ exports.INVITATIONS_REJECT_PAGE_FILE_PATH = INVITATIONS_REJECT_PAGE_FILE_PATH;
86
89
  exports.SPONSORS_FILE_PATH = SPONSORS_FILE_PATH;
87
90
  exports.CMS_FONT_FILE_PATH = CMS_FONT_FILE_PATH;
88
91
  exports.PAYMENTS_FILE_PATH = PAYMENTS_FILE_PATH;
@@ -7,13 +7,13 @@ export const getDefaultLocation = (eventRedirect, hasVirtualAccess = false) => {
7
7
 
8
8
  export const formatThirdPartyProviders = (providersArray) => {
9
9
  const providers = [
10
- { button_color: '#082238', provider_label: 'Continue with FNid', provider_param: '', provider_logo: '../img/logo_fn.svg', provider_logo_size: 35 },
10
+ { button_color: '#082238', provider_label: 'Sign in with FNid', provider_param: '', provider_logo: '../img/logo_fn.svg', provider_logo_size: 35 },
11
11
  ];
12
12
 
13
13
  const thirdPartyProviders = [
14
- { button_color: '#1877F2', provider_label: 'Continue with Facebook', provider_param: 'facebook', provider_logo: '../img/third-party-idp/logo_facebook.svg', provider_logo_size: 22 },
14
+ { button_color: '#1877F2', provider_label: 'Login with Facebook', provider_param: 'facebook', provider_logo: '../img/third-party-idp/logo_facebook.svg', provider_logo_size: 22 },
15
15
  { button_color: '#0A66C2', provider_label: 'Sign in with LinkedIn', provider_param: 'linkedin', provider_logo: '../img/third-party-idp/logo_linkedin.svg', provider_logo_size: 21 },
16
- { button_border_color:'var(--color_input_border_color)', button_color: '#000000', provider_label: 'Continue with Apple', provider_param: 'apple', provider_logo: '../img/third-party-idp/logo_apple.svg', provider_logo_size: 19 }
16
+ { button_border_color:'var(--color_input_border_color)', button_color: '#000000', provider_label: 'Sign in with Apple', provider_param: 'apple', provider_logo: '../img/third-party-idp/logo_apple.svg', provider_logo_size: 19 }
17
17
  ];
18
18
 
19
19
  return [...providers, ...thirdPartyProviders.filter(p => providersArray && providersArray.includes(p.provider_param))];
@@ -63,7 +63,7 @@ const filterMyEvents = (myEvents, events) => {
63
63
  return events.filter(ev => myEventsIds.includes(ev.id));
64
64
  };
65
65
 
66
- export const preFilterEvents = (events, filters, summitTimezone, userProfile, filterByAccessLevel, filterByMySchedule) => {
66
+ export const preFilterEvents = (events, filters, summitTimezone, userProfile, filterByAccessLevel, filterByMySchedule, hidePast) => {
67
67
  const {schedule_summit_events = []} = userProfile || {};
68
68
  let result = [...events];
69
69
 
@@ -75,10 +75,11 @@ export const preFilterEvents = (events, filters, summitTimezone, userProfile, fi
75
75
  result = filterEventsByAccessLevel(result, userProfile);
76
76
  }
77
77
 
78
- return getFilteredEvents(result, filters, summitTimezone);
78
+ return getFilteredEvents(result, filters, summitTimezone, hidePast);
79
79
  };
80
80
 
81
- export const getFilteredEvents = (events, filters, summitTimezone) => {
81
+ export const getFilteredEvents = (events, filters, summitTimezone, hidePast) => {
82
+ const localNow = Date.now() / 1000;
82
83
 
83
84
  return events.filter((ev) => {
84
85
  let valid = true;
@@ -90,8 +91,11 @@ export const getFilteredEvents = (events, filters, summitTimezone) => {
90
91
  valid = filters.date.values.includes(dateString);
91
92
  if (!valid) return false;
92
93
  }
93
-
94
- if (ev.type.show_always_on_schedule) return true;
94
+
95
+ if (ev.type.show_always_on_schedule) {
96
+ // hide past events when the flag is on
97
+ return !(hidePast && ev.end_date < localNow);
98
+ }
95
99
 
96
100
  if (filters.level?.values.length > 0) {
97
101
  valid = filters.level.values.some(l => l.toString().toLowerCase() === ev.level?.toLowerCase());
@@ -1,5 +1,5 @@
1
1
 
2
- export const getUrl = (scheme, host, pathname) => {
2
+ export const buildUrl = (scheme, host, pathname) => {
3
3
  if (!host) return null;
4
4
  const domain = `${scheme}://${host}`;
5
5
  return `${domain}${pathname ?? "/"}`;
@@ -1,26 +0,0 @@
1
- /**
2
- * Create dummy storage on the server-side and wrapper for localStorage on the client-side.
3
- * @see https://github.com/rt2zz/redux-persist/issues/1208#issuecomment-658695446
4
- * @see https://stackoverflow.com/questions/57781527/how-to-solve-console-error-redux-persist-failed-to-create-sync-storage-falli
5
- * @see https://github.com/vercel/next.js/discussions/15687#discussioncomment-45319
6
- */
7
-
8
- import createWebStorage from 'redux-persist/lib/storage/createWebStorage';
9
-
10
- const createNoopStorage = () => {
11
- return {
12
- getItem(_key) {
13
- return Promise.resolve(null);
14
- },
15
- setItem(_key, value) {
16
- return Promise.resolve(value);
17
- },
18
- removeItem(_key) {
19
- return Promise.resolve();
20
- },
21
- };
22
- };
23
-
24
- const storage = typeof window !== 'undefined' ? createWebStorage('local') : createNoopStorage();
25
-
26
- export default storage;