diff --git a/package-lock.json b/package-lock.json index af1711335..c83f6d29a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -111,6 +111,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -892,6 +893,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -1454,6 +1456,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz", "integrity": "sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw==", + "peer": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-module-imports": "^7.18.6", @@ -3187,6 +3190,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -4017,6 +4021,7 @@ "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -4389,6 +4394,7 @@ "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4456,6 +4462,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -5474,6 +5481,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -6502,6 +6510,7 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -7418,6 +7427,7 @@ "version": "3.11.0", "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.11.0.tgz", "integrity": "sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==", + "peer": true, "dependencies": { "array.prototype.flat": "^1.2.3", "cheerio": "^1.0.0-rc.3", @@ -7736,6 +7746,7 @@ "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "7.12.11", "@eslint/eslintrc": "^0.4.3", @@ -8090,6 +8101,7 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -11058,6 +11070,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "peer": true, "dependencies": { "@jest/core": "^27.5.1", "import-local": "^3.0.2", @@ -13850,6 +13863,7 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -14137,6 +14151,7 @@ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.23.tgz", "integrity": "sha512-Q5bo1yYOcH2wbBPP4tGmcY5VKsFkQcjUDh66YjrbneAFB3vNKQwLvteRFLuLiU17rA5SDl3UMcMJLD9VS8ng2Q==", "license": "MIT", + "peer": true, "dependencies": { "@types/bson": "1.x || 4.0.x", "@types/mongodb": "^3.5.27", @@ -15405,6 +15420,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", @@ -16397,6 +16413,7 @@ "version": "6.0.15", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -16608,6 +16625,7 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -16760,6 +16778,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -16911,6 +16930,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -16964,6 +16984,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -17202,6 +17223,7 @@ "version": "8.56.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -17855,6 +17877,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "license": "MIT", + "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -19615,6 +19638,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -19920,19 +19944,6 @@ "node": ">=4" } }, - "node_modules/type-fest": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.9.0.tgz", - "integrity": "sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg==", - "optional": true, - "peer": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -20348,6 +20359,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", @@ -20416,6 +20428,7 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -20466,6 +20479,7 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", "license": "MIT", + "peer": true, "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -20524,6 +20538,7 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -20658,6 +20673,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -21014,6 +21030,7 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", diff --git a/src/APIFunctions/SCEvents.js b/src/APIFunctions/SCEvents.js index 154d6e9d6..15a243c07 100644 --- a/src/APIFunctions/SCEvents.js +++ b/src/APIFunctions/SCEvents.js @@ -27,3 +27,29 @@ export async function getAllSCEvents() { return status; } + +export async function getEventByID(id) { + let status = new ApiResponse(); + + try { + const url = new URL(`/events/${id}`, SCEVENTS_API_URL); + const res = await fetch(url.href, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); + + if (res.ok) { + const result = await res.json(); + status.responseData = result; + } else { + status.error = true; + } + } catch (err) { + status.error = true; + status.responseData = err; + } + + return status; +} diff --git a/src/Pages/Events/Events.js b/src/Pages/Events/Events.js index 9e0ad3db7..128f9e9c5 100644 --- a/src/Pages/Events/Events.js +++ b/src/Pages/Events/Events.js @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import config from '../../config/config.json'; -import { Redirect } from 'react-router-dom'; +import { Link, Redirect } from 'react-router-dom'; import { getAllSCEvents } from '../../APIFunctions/SCEvents'; function CalendarIcon() { @@ -41,7 +41,7 @@ function PinIcon() { function EventCard({ event }) { return ( -
+

{event.name || 'Untitled Event'}

@@ -71,6 +71,15 @@ function EventCard({ event }) { {event.description}

)} + +
+ + Register + +
); } diff --git a/src/Pages/Events/EventsRegistation.js b/src/Pages/Events/EventsRegistation.js new file mode 100644 index 000000000..c78920bbb --- /dev/null +++ b/src/Pages/Events/EventsRegistation.js @@ -0,0 +1,224 @@ +import React, { useState, useEffect } from 'react'; +import { useParams, useHistory, Redirect } from 'react-router-dom'; +import config from '../../config/config.json'; +import { getEventByID } from '../../APIFunctions/SCEvents'; + +function ArrowLeftIcon() { + return ( + + ); +} + +export default function EventRegistration() { + const { id } = useParams(); + const history = useHistory(); + const isSCEventsEnabled = Boolean(config.SCEvents?.ENABLED); + const [event, setEvent] = useState(null); + const [formData, setFormData] = useState({}); + const [isLoading, setIsLoading] = useState(true); + const [hasError, setHasError] = useState(false); + + useEffect(() => { + if (!isSCEventsEnabled) { + return; + } + + async function fetchEvent() { + setIsLoading(true); + const response = await getEventByID(id); + if (!response.error && response.responseData) { + setEvent(response.responseData); + const initialData = {}; + (response.responseData.registration_form || []).forEach(field => { // eslint-disable-line camelcase + initialData[field.id] = field.type === 'checkbox' ? [] : ''; + }); + setFormData(initialData); + } else { + setHasError(true); + } + setIsLoading(false); + } + fetchEvent(); + }, [id, isSCEventsEnabled]); + + if (!isSCEventsEnabled) { + return ; + } + + const handleInputChange = (fieldId, value, type) => { + if (type === 'checkbox') { + const currentValues = formData[fieldId] || []; + if (currentValues.includes(value)) { + setFormData({ ...formData, [fieldId]: currentValues.filter(v => v !== value) }); + } else { + setFormData({ ...formData, [fieldId]: [...currentValues, value] }); + } + } else { + setFormData({ ...formData, [fieldId]: value }); + } + }; + + const handleSubmit = (e) => { + e.preventDefault(); + + const summary = (event.registration_form || []).map(field => { // eslint-disable-line camelcase + const answer = formData[field.id]; + const displayAnswer = Array.isArray(answer) ? answer.join(', ') : answer; + return `- ${field.question}: ${displayAnswer || 'N/A'}`; + }).join('\n'); + + const message = `Registration Successful for: ${event.name}!\n\nSummary of your responses:\n${summary}`; + + alert(message); + history.push('/events'); + }; + + if (isLoading) { + return ( +
+

Loading registration form...

+
+ ); + } + + if (hasError || !event) { + return ( +
+
+

Failed to load event details.

+ +
+
+ ); + } + + return ( +
+ {/* Background Blurs */} +
+
+
+
+ +
+ + +

+ {event.name} +

+ +
+
+ {(event.registration_form || []).map((field) => ( // eslint-disable-line camelcase +
+ + + {field.type === 'textbox' && ( + handleInputChange(field.id, e.target.value)} + /> + )} + + {field.type === 'dropdown' && ( +
+ +
+ + + +
+
+ )} + + {field.type === 'multiple_choice' && ( +
+ {(field.answer_options || []).map(opt => ( // eslint-disable-line camelcase + + ))} +
+ )} + + {field.type === 'checkbox' && ( +
+ {(field.answer_options || []).map(opt => ( // eslint-disable-line camelcase + + ))} +
+ )} +
+ ))} + +
+ +
+
+
+
+
+ ); +} diff --git a/src/Routes.js b/src/Routes.js index ee643e3ea..97bc0e4b3 100644 --- a/src/Routes.js +++ b/src/Routes.js @@ -20,6 +20,7 @@ import CardReader from './Pages/CardReader/CardReader.js'; import AuditLogsPage from './Pages/AuditLog/AuditLog.js'; import PermissionRequestPage from './Pages/PermissionRequest/PermissionRequest.js'; import EventsPage from './Pages/Events/Events.js'; +import EventRegistration from './Pages/Events/EventsRegistation.js'; // Declare an enum for permission check export const allowedIf = { @@ -203,6 +204,12 @@ export const signedOutRoutes = [ path: '/events', pageName: 'Events' }, + { + Component: EventRegistration, + path: '/events/:id/register', + pageName: 'Event Registration', + hideFromShortcutSuggestions: true + }, { Component: EmailPreferencesPage, path: '/emailPreferences',