Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {
booleanField
} from "../../../fields";

import {
BADGE_QR_PAGE_FILE_PATH
} from "@utils/filePath";

const badgeQrPage = {
label: "Badge QR Page",
name: "badge-qr-page",
file: BADGE_QR_PAGE_FILE_PATH,
fields: [
booleanField({
label: "Enable Badge QR Page",
name: "enabled",
required: false
})
]
};

export default badgeQrPage;

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

module.exports = `
type BadgeQrPageJson implements Node {
enabled: Boolean
}
`;
4 changes: 3 additions & 1 deletion src/cms/config/collections/defaultPagesCollection/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import lobbyPage from "./lobbyPage";
import expoHallPage from "./expoHallPage";
import invitationsRejectPage from "./invitationsRejectPage";
import mySchedulePage from "./mySchedulePage";
import badgeQrPage from "./badgeQrPage";

const defaultPagesCollection = {
...collectionDefaults({
Expand All @@ -18,7 +19,8 @@ const defaultPagesCollection = {
lobbyPage,
expoHallPage,
invitationsRejectPage,
mySchedulePage
mySchedulePage,
badgeQrPage
]
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ const lobbyPageTypeDefs = require("./lobbyPage/typeDefs");
const expoHallPageTypeDefs = require("./expoHallPage/typeDefs");
const invitationsRejectPageTypeDefs = require("./invitationsRejectPage/typeDefs");
const mySchedulePageTypeDefs = require("./mySchedulePage/typeDefs");
const badgeQrPageTypeDefs = require("./badgeQrPage/typeDefs")

module.exports = [
marketingPageTypeDefs,
lobbyPageTypeDefs,
expoHallPageTypeDefs,
invitationsRejectPageTypeDefs,
mySchedulePageTypeDefs
mySchedulePageTypeDefs,
badgeQrPageTypeDefs
].join("");
8 changes: 6 additions & 2 deletions src/components/Navbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { connect } from "react-redux";
import { navigate } from "gatsby";
import NavbarTemplate from "./template";

import { userHasAccessLevel, VIRTUAL_ACCESS_LEVEL } from "@utils/authorizedGroups";
import { userHasAccessLevel, VIRTUAL_ACCESS_LEVEL, userHasCheckedInBadge } from "@utils/authorizedGroups";
import { getDefaultLocation } from "@utils/loginUtils";

import { PHASES } from "@utils/phasesUtils";
Expand All @@ -29,6 +29,8 @@ const Navbar = ({
userProfile ? userHasAccessLevel(userProfile.summit_tickets, VIRTUAL_ACCESS_LEVEL) : false
, [userProfile]);

const hasSummitHallCheckedIn = userProfile ? userHasCheckedInBadge(userProfile.summit_tickets) : false;

const defaultPath = getDefaultLocation(eventRedirect, hasVirtualBadge);

const meetsUserRequirement = (userRequirement) => {
Expand Down Expand Up @@ -84,7 +86,9 @@ const Navbar = ({
(item.pageRestriction.includes(PAGE_RESTRICTIONS.marketing) && isMarketingPage(currentPath)) ||
(item.pageRestriction.includes(PAGE_RESTRICTIONS.lobby) && isLobbyPage(currentPath)) ||
(item.pageRestriction.includes(PAGE_RESTRICTIONS.show) && isShowPage(currentPath)) ||
(item.pageRestriction.includes(PAGE_RESTRICTIONS.customPage) && isCustomPage(currentPath));
(item.pageRestriction.includes(PAGE_RESTRICTIONS.badge) && hasSummitHallCheckedIn) ||
(item.pageRestriction.includes(PAGE_RESTRICTIONS.customPage) && isCustomPage(currentPath))
;

return item.display &&
meetsUserRequirement(item.userRequirement) &&
Expand Down
1 change: 1 addition & 0 deletions src/content/badge-qr-page/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
9 changes: 9 additions & 0 deletions src/content/navbar/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@
"ANY"
]
},
{
"title": "Show Badge QR",
"link": "/a/badge",
"display": true,
"requiresAuth": true,
"pageRestriction": [
"BADGE"
]
},
{
"title": "My Tickets",
"link": "/a/my-tickets",
Expand Down
16 changes: 14 additions & 2 deletions src/pages/a/[...].js
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ import ShowOpenRoute from "../../routes/ShowOpenRoute";
import WithBadgeRoute from "../../routes/WithBadgeRoute";
import PosterDetailPage from "../../templates/poster-detail-page";
import MyTicketsPage from "../../templates/my-tickets-page";
import BadgePage from "../../templates/badge-page";
import withRealTimeUpdates from "../../utils/real_time_updates/withRealTimeUpdates";
import withFeedsWorker from "../../utils/withFeedsWorker";
import Seo from "../../components/Seo";
import Link from "../../components/Link";
import { titleFromPathname } from "../../utils/urlFormating";
import {graphql} from "gatsby";
import WithAttendeeCheckedInRoute from "../../routes/WithAttendeeCheckedInRoute";

const mySchedulePage = ({ location, summitPhase,isLoggedUser, user, allowClick, title, key }) => {
return <SchedulePage
Expand Down Expand Up @@ -56,13 +58,18 @@ export const appQuery = graphql`
key
needsTicketAuthz
}
badgeQrPageJson {
enabled
}
}
`;


const App = ({ isLoggedUser, user, summitPhase, allowClick = true, data }) => {

const { mySchedulePageJson } = data;
const { mySchedulePageJson, badgeQrPageJson } = data;

console.log("CHECK!", badgeQrPageJson);

return (
<Location>
Expand All @@ -88,13 +95,18 @@ const App = ({ isLoggedUser, user, summitPhase, allowClick = true, data }) => {
<PostersPage path="/posters/:trackGroupId" location={location} />
<PosterDetailPage path="/poster/:presentationId/" isLoggedIn={isLoggedUser} user={user} location={location} />
{ mySchedulePageJson.needsTicketAuthz && mySchedulePage({location, summitPhase,isLoggedUser, user, allowClick, title: mySchedulePageJson.title, key: mySchedulePageJson.key }) }
{badgeQrPageJson.enabled &&
<WithAttendeeCheckedInRoute path="/" isLoggedIn={isLoggedUser} user={user} location={location}>
<BadgePage path="/badge" summitPhase={summitPhase} isLoggedIn={isLoggedUser} user={user} location={location} />
</WithAttendeeCheckedInRoute>
}
<ShowOpenRoute path="/" summitPhase={summitPhase} isLoggedIn={isLoggedUser} user={user} location={location}>
<WithBadgeRoute path="/event/:eventId" summitPhase={summitPhase} isLoggedIn={isLoggedUser} user={user} location={location}>
<EventPage path="/" summitPhase={summitPhase} isLoggedIn={isLoggedUser} user={user} location={location} />
</WithBadgeRoute>
<SponsorPage path="/sponsor/:sponsorId" summitPhase={summitPhase} isLoggedIn={isLoggedUser} user={user} location={location} />
<ExpoHallPage path="/sponsors/" summitPhase={summitPhase} isLoggedIn={isLoggedUser} user={user} location={location} />
</ShowOpenRoute>
</ShowOpenRoute>
</WithAuthzRoute>
</WithAuthRoute>
</Router>
Expand Down
41 changes: 41 additions & 0 deletions src/routes/WithAttendeeCheckedInRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, {useEffect, useState, useMemo} from "react";
import {connect} from "react-redux";
import {navigate} from "gatsby";
import { userHasCheckedInBadge } from "../utils/authorizedGroups";

/**
*
* @param children
* @param isLoggedIn
* @param location
* @param userProfile
* @returns {JSX.Element|null|*}
* @constructor
*/
const withAttendeeCheckedIn = ({
children,
isLoggedIn,
location,
userProfile
}) => {

const isAttendeeCheckedIn = userHasCheckedInBadge(userProfile.summit_tickets);

if (!isLoggedIn) {
navigate("/", {state: {backUrl: `${location.pathname}`,},});
return null;
}

// has no checked badge -> redirect
if (!isAttendeeCheckedIn) {
navigate("/", {state: {backUrl: `${location.pathname}`,},});
}

return children;
};

const mapStateToProps = ({userState}) => ({
userProfile: userState.userProfile
});

export default connect(mapStateToProps, {})(withAttendeeCheckedIn);
114 changes: 114 additions & 0 deletions src/templates/badge-page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React, { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'

import Dropdown from 'openstack-uicore-foundation/lib/components/inputs/dropdown'
import QRCode from "react-qr-code";

import Layout from '../components/Layout'
import { userHasCheckedInBadge } from '../utils/authorizedGroups';

export const BadgePageTemplate = ({ user }) => {

const hasBadgeChecked = userHasCheckedInBadge(user.summit_tickets);

const [currentTicket, setCurrentTicket] = useState(null);
const [userTickets, setUserTickets] = useState([]);
const [badgesDDL, setBadgeDDL] = useState([]);

useEffect(() => {
// filter tickets with a badge that has access level IN_PERSON
const inPersonTickets = user?.summit_tickets.filter(t => t.badge?.type?.access_levels.some((al) => al.name.includes("IN_PERSON")));
setUserTickets(inPersonTickets);
const formattedTickets = inPersonTickets.map(e => ({ label: e.number, value: e.id }));
setBadgeDDL(formattedTickets || []);
}, []);

useEffect(() => {
const firstTicket = userTickets.find(e => e.qr_code);
setCurrentTicket(firstTicket);
}, [userTickets]);

const handleTicketChange = (ev) => {
const { target: { value } } = ev;
const newTicket = user.summit_tickets.find(e => e.id === value);
setCurrentTicket(newTicket);
}

return (
<div className="px-6 py-6 mb-6">

<h2>Badge QR</h2>
<div className="columns mt-5">
<div className={"column is-half-desktop is-full-mobile "}>
<Dropdown
id="user_tickets"
placeholder="User Tickets"
value={currentTicket?.id}
onChange={handleTicketChange}
options={badgesDDL}
styles={{
container: (base) => ({
...base,
width: "100%",
}),
control: (base) => ({
...base,
width: "100%",
}),
option: (base) => ({
...base,
width: 'max-content',
minWidth: '100%'
}),
menu: (base) => ({
...base,
maxWidth: "100%",
}),
}}
/>
</div>
</div>
<div className="columns mt-3">
<div className={"column is-half-desktop is-full-mobile"}>
{currentTicket &&
<QRCode
size={256}
style={{ height: "auto", maxWidth: "100%", width: "100%" }}
value={currentTicket.badge.qr_code}
viewBox={`0 0 256 256`}
/>
}
</div>
</div>
</div>
)
};

const BadgePage = (
{
location,
user,
}
) => {
return (
<Layout location={location}>
<BadgePageTemplate
user={user} />
</Layout>
)
};

BadgePage.propTypes = {
user: PropTypes.object,
};

BadgePageTemplate.propTypes = {
user: PropTypes.object
};

const mapStateToProps = ({ userState }) => ({
user: userState.userProfile,
});

export default connect(mapStateToProps, {})(BadgePage);
4 changes: 4 additions & 0 deletions src/utils/authorizedGroups.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,7 @@ export const filterEventsByAccessLevels = (originalEvents , user) => {
return isAuthorizedBadge(ev, summitTickets);
});
}

export const userHasCheckedInBadge = (summitTickets) => {
return summitTickets.some(t => t.owner.summit_hall_checked_in === true);
}
2 changes: 2 additions & 0 deletions src/utils/filePath.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const MARKETING_SETTINGS_FILE_PATH = `${DATA_DIR_PATH}/marketing-settings.json`;
const MAINTENANCE_PATH_NAME = `maintenance`;
const EXPO_HALL_PAGE_FILE_PATH = `${STATIC_CONTENT_DIR_PATH}/expo-hall-page/index.json`;
const INVITATIONS_REJECT_PAGE_FILE_PATH = `${STATIC_CONTENT_DIR_PATH}/invitations-reject-page/index.json`;
const BADGE_QR_PAGE_FILE_PATH = `${STATIC_CONTENT_DIR_PATH}/badge-qr-page/index.json`;
const SPONSORS_FILE_NAME = "sponsors.json";
const SPONSORS_FILE_PATH = `${STATIC_CONTENT_DIR_PATH}/${SPONSORS_FILE_NAME}`;
const CMS_FONT_FILE_PATH = "/static/fonts/"
Expand Down Expand Up @@ -94,6 +95,7 @@ exports.MARKETING_SETTINGS_FILE_PATH = MARKETING_SETTINGS_FILE_PATH;
exports.MAINTENANCE_PATH_NAME = MAINTENANCE_PATH_NAME;
exports.EXPO_HALL_PAGE_FILE_PATH = EXPO_HALL_PAGE_FILE_PATH;
exports.INVITATIONS_REJECT_PAGE_FILE_PATH = INVITATIONS_REJECT_PAGE_FILE_PATH;
exports.BADGE_QR_PAGE_FILE_PATH = BADGE_QR_PAGE_FILE_PATH;
exports.SPONSORS_FILE_PATH = SPONSORS_FILE_PATH;
exports.CMS_FONT_FILE_PATH = CMS_FONT_FILE_PATH;
exports.PAYMENTS_FILE_PATH = PAYMENTS_FILE_PATH;
Expand Down
1 change: 1 addition & 0 deletions src/utils/pageAccessConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const PAGE_RESTRICTIONS = {
marketing: "MARKETING",
lobby: "LOBBY",
show: "SHOW",
badge: "BADGE",
customPage: "CUSTOM_PAGE"
};

Expand Down