From e7b0d23a87468fb3963fa2fb1a0963b01eb2ecdd Mon Sep 17 00:00:00 2001 From: Nikhil Garg Date: Sun, 5 Mar 2023 16:56:20 -0800 Subject: [PATCH 1/9] update to new topocons and eslint --fix --- .eslintrc.js | 13 + .gitignore | 3 + jsconfig.json | 8 + next.config.js | 12 +- package.json | 6 +- src/components/Alert.js | 103 ++-- src/components/Badge.js | 36 +- src/components/Breadcrumbs.js | 96 +-- src/components/Calendar.js | 205 +++---- src/components/Confidential.js | 10 +- src/components/ContactBox.js | 23 +- src/components/DaysUntilEvent.js | 46 +- src/components/DocsCallout.js | 8 +- src/components/EmailTemplate.js | 62 +- src/components/Event.js | 54 +- src/components/EventGroup.js | 22 +- src/components/EventRestriction.js | 266 +++++---- src/components/EventRestrictionBox.js | 35 +- src/components/InfoBox.js | 64 +- src/components/Kbd.js | 9 +- src/components/LinkEventRestrictionsModal.js | 161 ++--- src/components/MetadataBox.js | 44 +- src/components/Opossum.js | 18 +- src/components/Page.js | 147 ++--- src/components/PromoCodeBox.js | 36 +- src/components/RegistrationGraph.js | 143 ++--- .../RegistrationsToggleWithChecklist.js | 151 +++-- src/components/ScheduleBox.js | 38 +- src/components/SponsorBox.js | 284 ++++----- src/components/SponsorOverview.js | 20 +- src/components/Ticket.js | 305 +++++----- src/components/TicketBox.js | 48 +- src/components/VenueInfo.js | 76 +-- src/components/forms/EditSpecificMetadata.js | 146 +++-- src/components/forms/EmailTemplate.js | 554 +++++++++--------- src/components/forms/Event.js | 531 ++++++++--------- src/components/forms/EventGroup.js | 414 ++++++------- src/components/forms/EventRestriction.js | 338 +++++------ src/components/forms/Guardian.js | 354 +++++------ src/components/forms/Notes.js | 128 ++-- src/components/forms/Person.js | 342 +++++------ src/components/forms/PromoCode.js | 513 ++++++++-------- src/components/forms/ScheduleItem.js | 486 +++++++-------- src/components/forms/Sponsor.js | 404 ++++++------- src/components/forms/Ticket.js | 442 +++++++------- src/components/forms/Venue.js | 428 +++++++------- src/fetch.js | 28 +- src/pages/404.js | 12 +- src/pages/500.js | 14 +- src/pages/_app.js | 45 +- src/pages/_document.js | 4 +- src/pages/admin/emailTemplates/index.js | 67 ++- src/pages/admin/index.js | 20 +- src/pages/api/auth/[...nextauth].js | 40 +- src/pages/events/[event]/advancedConfig.js | 199 +++---- src/pages/events/[event]/eventRestrictions.js | 79 ++- src/pages/events/[event]/index.js | 226 +++---- src/pages/events/[event]/notification.js | 168 +++--- src/pages/events/[event]/preRegistrations.js | 146 ++--- .../events/[event]/promoCodes/[promoCode].js | 99 ++-- src/pages/events/[event]/promoCodes/index.js | 79 ++- .../events/[event]/schedule/[scheduleitem].js | 114 ++-- src/pages/events/[event]/schedule/index.js | 52 +- src/pages/events/[event]/sponsors.js | 62 +- .../events/[event]/tickets/[ticket]/index.js | 247 +++++--- src/pages/events/[event]/tickets/index.js | 232 ++++---- src/pages/events/[event]/tickets/scan.js | 54 +- src/pages/events/index.js | 84 +-- src/pages/groups/[group]/index.js | 88 ++- src/pages/groups/index.js | 60 +- src/pages/index.js | 64 +- src/pages/token.js | 43 +- src/pages/unauthorized.js | 37 +- src/providers/query.js | 8 +- src/token.js | 72 +-- yarn.lock | 367 ++++++------ 76 files changed, 5371 insertions(+), 5071 deletions(-) create mode 100644 jsconfig.json diff --git a/.eslintrc.js b/.eslintrc.js index a4f4d63..5dd1b9b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,16 @@ module.exports = { + parserOptions: { + ecmaVersion: 2020, + }, extends: '@codeday', + settings: { + 'import/resolver': { + exports: { + require: false, + browser: false, + conditions: [], + unsafe: false, + }, + }, + }, }; diff --git a/.gitignore b/.gitignore index e7f4778..99dae06 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,6 @@ yarn-error.log* .vercel .env + +.yalc +yalc.lock \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..eb1afa8 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "baseUrl": "./src", + "checkJs": true, + "jsx": "react" + }, + "exclude": ["node_modules", ".next"] +} diff --git a/next.config.js b/next.config.js index 7bc5e77..d0f2e4f 100644 --- a/next.config.js +++ b/next.config.js @@ -1,5 +1,5 @@ -const withBundleAnalyzer = require("@next/bundle-analyzer")({ - enabled: process.env.ANALYZE === "true", +const withBundleAnalyzer = require('@next/bundle-analyzer')({ + enabled: process.env.ANALYZE === 'true', }); module.exports = withBundleAnalyzer({ @@ -12,7 +12,7 @@ module.exports = withBundleAnalyzer({ clientId: process.env.AUTH0_CLIENT_ID, clientSecret: process.env.AUTH0_CLIENT_SECRET, domain: process.env.AUTH0_DOMAIN, - issuer: `https://` + process.env.AUTH0_DOMAIN, + issuer: `https://${process.env.AUTH0_DOMAIN}`, roles: { employee: process.env.AUTH0_EMPLOYEE_ROLE, admin: process.env.AUTH0_ADMIN_ROLE, @@ -28,11 +28,13 @@ module.exports = withBundleAnalyzer({ }, appUrl: process.env.APP_URL, }, - webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => { + webpack: (config, { + buildId, dev, isServer, defaultLoaders, webpack, + }) => { config?.module?.rules.push({ test: /\.(graphql|gql)$/, exclude: /node_modules/, - loader: "graphql-tag/loader", + loader: 'graphql-tag/loader', }); return config; }, diff --git a/package.json b/package.json index c28880e..cc1c820 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,10 @@ "dependencies": { "@chakra-ui/icons": "^2.0.17", "@chakra-ui/react": "^2.5.1", - "@codeday/topo": "^9.1.1", + "@codeday/topo": "^9.2.0", + "@codeday/topocons": "^2.0.2", "@emotion/react": "^11.0.0", "@emotion/styled": "^11.0.0", - "@codeday/topocons": "^1.5.0", "@emotion/utils": "1.0.0", "@headwayapp/react-widget": "^0.0.4", "@rjsf/antd": "^3.1.0", @@ -72,6 +72,8 @@ "cross-env": "^7.0.3", "eslint": "^7.32.0", "eslint-config-next": "11.1.0", + "eslint-import-resolver-exports": "^1.0.0-beta.5", + "formdata-node": "^5.0.0", "npm-check": "^5.9.2" } } diff --git a/src/components/Alert.js b/src/components/Alert.js index 6d523e8..0c09950 100644 --- a/src/components/Alert.js +++ b/src/components/Alert.js @@ -1,61 +1,64 @@ import React from 'react'; -import * as Icon from '@codeday/topocons/Icon'; +import { + UiError, UiInfo, UiOk, UiWarning, +} from '@codeday/topocons'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { Icon } from '@chakra-ui/react'; import Badge from './Badge'; -import {useColorModeValue} from "@codeday/topo/Theme"; -export default function Alert({children, ...props}) { - return ( - - {' '}{children} - - ); +export default function Alert({ children, ...props }) { + return ( + + {' '}{children} + + ); } -export function InfoAlert({children, ...props}) { - return ( - - {' '}{children} - - ); + {...props} + > + {' '}{children} + + ); } -export function WarningAlert({children, ...props}) { - return ( - - {' '}{children} - - ); +export function WarningAlert({ children, ...props }) { + return ( + + {' '}{children} + + ); } -export function GoodAlert({children, ...props}) { - return ( - - {' '}{children} - - ); +export function GoodAlert({ children, ...props }) { + return ( + + {' '}{children} + + ); } diff --git a/src/components/Badge.js b/src/components/Badge.js index 65d31b7..c16de46 100644 --- a/src/components/Badge.js +++ b/src/components/Badge.js @@ -1,21 +1,21 @@ import React from 'react'; -import {Box} from "@codeday/topo/Atom"; -import {useColorModeValue} from "@codeday/topo/Theme"; +import { Box } from '@codeday/topo/Atom'; +import { useColorModeValue } from '@codeday/topo/Theme'; -export default function Badge({children, ...props}) { - return ( - - {children} - - ); +export default function Badge({ children, ...props }) { + return ( + + {children} + + ); } diff --git a/src/components/Breadcrumbs.js b/src/components/Breadcrumbs.js index d3c0008..2eeefa7 100644 --- a/src/components/Breadcrumbs.js +++ b/src/components/Breadcrumbs.js @@ -1,55 +1,55 @@ -import React, {useEffect, useState} from 'react'; -import {useRouter} from 'next/router'; -import {Breadcrumb, BreadcrumbItem, BreadcrumbLink,} from '@chakra-ui/react'; +import React, { useEffect, useState } from 'react'; +import { useRouter } from 'next/router'; +import { Breadcrumb, BreadcrumbItem, BreadcrumbLink } from '@chakra-ui/react'; export default function Breadcrumbs({ - group, event, ticket, scheduleitem, code, - }) { - const router = useRouter(); - const [breadcrumbs, setBreadcrumbs] = useState(null); - const convertBreadcrumb = (string) => { - if (group && string === group.id) return group.name; - if (event && string === event.id) return event.name; - if (ticket && string === ticket.id) return `${ticket.firstName} ${ticket.lastName}`; - if (scheduleitem && string === scheduleitem.id) return scheduleitem.name; - if (code && string === code.id) return code.code - // https://stackoverflow.com/a/4149393 - return string - .replace(/([A-Z])/g, ' $1') - .replace(/^./, (str) => str.toUpperCase()); - }; + group, event, ticket, scheduleitem, code, +}) { + const router = useRouter(); + const [breadcrumbs, setBreadcrumbs] = useState(null); + const convertBreadcrumb = (string) => { + if (group && string === group.id) return group.name; + if (event && string === event.id) return event.name; + if (ticket && string === ticket.id) return `${ticket.firstName} ${ticket.lastName}`; + if (scheduleitem && string === scheduleitem.id) return scheduleitem.name; + if (code && string === code.id) return code.code; + // https://stackoverflow.com/a/4149393 + return string + .replace(/([A-Z])/g, ' $1') + .replace(/^./, (str) => str.toUpperCase()); + }; - useEffect(() => { - if (router) { - const linkPath = router.asPath.split('/'); - linkPath.shift(); - const pathArray = linkPath.map((path, i) => ({ - breadcrumb: path, - href: `/${linkPath.slice(0, i + 1).join('/')}` - })); + useEffect(() => { + if (router) { + const linkPath = router.asPath.split('/'); + linkPath.shift(); + const pathArray = linkPath.map((path, i) => ({ + breadcrumb: path, + href: `/${linkPath.slice(0, i + 1).join('/')}`, + })); - setBreadcrumbs(pathArray); - } - }, [router]); - - if (!breadcrumbs) { - return null; + setBreadcrumbs(pathArray); } + }, [router]); + + if (!breadcrumbs) { + return null; + } - return ( - - {/* */} - {/* */} - {/* CLEAR */} - {/* */} - {/* */} - {breadcrumbs.map((breadcrumb, i) => ( - - - {convertBreadcrumb(breadcrumb.breadcrumb)} - - - ))} - - ); + return ( + + {/* */} + {/* */} + {/* CLEAR */} + {/* */} + {/* */} + {breadcrumbs.map((breadcrumb, i) => ( + + + {convertBreadcrumb(breadcrumb.breadcrumb)} + + + ))} + + ); } diff --git a/src/components/Calendar.js b/src/components/Calendar.js index f92e483..59f1a63 100644 --- a/src/components/Calendar.js +++ b/src/components/Calendar.js @@ -1,112 +1,115 @@ -import React, {useEffect} from 'react'; -import {Box, Divider, Text} from "@codeday/topo/Atom"; +import React, { useEffect } from 'react'; +import { Box, Divider, Text } from '@codeday/topo/Atom'; import moment from 'moment-timezone'; import seed from 'random-seed'; -import {useTheme} from '@codeday/topo/utils'; -import {GoodAlert, InfoAlert, WarningAlert} from './Alert'; +import { useTheme } from '@codeday/topo/utils'; +import { GoodAlert, InfoAlert, WarningAlert } from './Alert'; export const eventColors = { - Meal: 'green', - Special: 'yellow', - Event: 'gray', - Workshop: 'orange', - Livestream: 'purple', - Deadline: 'red', - 'Gaming Tournament': 'pink', + Meal: 'green', + Special: 'yellow', + Event: 'gray', + Workshop: 'orange', + Livestream: 'purple', + Deadline: 'red', + 'Gaming Tournament': 'pink', }; export default function Calendar({ - event, border, children, ...props - }) { - const schedule = event.schedule.sort((a, b) => (moment(a.start).isAfter(moment(b.start)) ? 1 : -1)); - if (schedule.length === 0) return <>; - const displayStarts = moment(schedule[0].start); - const displayEnds = moment(schedule[schedule.length - 1].start); - useEffect(() => { - if (typeof window !== 'undefined') { - moment.tz.setDefault(Intl.DateTimeFormat().resolvedOptions().timeZone); - } - }, [typeof window]); - const eventsByDay = {}; - schedule.forEach((e) => { - const day = moment(e.start).startOf('day').format('YYYY-MM-DD'); - if (!(day in eventsByDay)) eventsByDay[day] = []; - eventsByDay[day].push(e); - }); - - const drawDays = []; - let day = displayStarts.clone(); - while (day.isSameOrBefore(displayEnds)) { - drawDays.push(day.startOf('day')); - day = day.clone().add(1, 'day'); + event, border, children, ...props +}) { + const schedule = event.schedule.sort((a, b) => (moment(a.start).isAfter(moment(b.start)) ? 1 : -1)); + if (schedule.length === 0) return <>; + const displayStarts = moment(schedule[0].start); + const displayEnds = moment(schedule[schedule.length - 1].start); + useEffect(() => { + if (typeof window !== 'undefined') { + moment.tz.setDefault(Intl.DateTimeFormat().resolvedOptions().timeZone); } - return ( - - {drawDays.map((date) => ( - <> - - {date.format('dddd, MMM Do')} - - {(date.format('YYYY-MM-DD') in eventsByDay) - ? eventsByDay[date.format('YYYY-MM-DD')].sort((a, b) => (moment(a.start).isAfter(moment(b.start)) ? 1 : -1)).map((e) => { - const {colors} = useTheme(); - const colorHues = Object.keys(colors); - const baseColor = eventColors[e.type || 'Event'] || colorHues[seed(e.type.toLowerCase()).intBetween(0, colorHues.length)]; - return ( - - { + const day = moment(e.start).startOf('day').format('YYYY-MM-DD'); + if (!(day in eventsByDay)) eventsByDay[day] = []; + eventsByDay[day].push(e); + }); + + const drawDays = []; + let day = displayStarts.clone(); + while (day.isSameOrBefore(displayEnds)) { + drawDays.push(day.startOf('day')); + day = day.clone().add(1, 'day'); + } + return ( + + {drawDays.map((date) => ( + <> + + {date.format('dddd, MMM Do')} + + + {(date.format('YYYY-MM-DD') in eventsByDay) + ? eventsByDay[date.format('YYYY-MM-DD')].sort((a, b) => (moment(a.start).isAfter(moment(b.start)) ? 1 : -1)).map((e) => { + const { colors } = useTheme(); + const colorHues = Object.keys(colors); + const baseColor = eventColors[e.type || 'Event'] || colorHues[seed(e.type.toLowerCase()).intBetween(0, colorHues.length)]; + return ( + + - {e.type || 'Event'} - - - {e.name || 'TBA'} - - {e.displayTime} - - {e.hostName}{e.hostPronoun ? `(${e.hostPronoun})` : null} - {e.internal ? Internal : e.finalized ? - Finalized : - Not Finalized} - {e.description} - - - ); - }) : null} + borderBottomWidth={1} + > + {e.type || 'Event'} + + + {e.name || 'TBA'} + + {e.displayTime} + + {e.hostName}{e.hostPronoun ? `(${e.hostPronoun})` : null} + {e.internal ? Internal : e.finalized + ? Finalized + : Not Finalized} + {e.description} - - ))} - - ); + + ); + }) : null} + + + ))} + + ); } diff --git a/src/components/Confidential.js b/src/components/Confidential.js index 9cdbc99..2d0a4ca 100644 --- a/src/components/Confidential.js +++ b/src/components/Confidential.js @@ -1,8 +1,8 @@ import React from 'react'; -import Badge from "./Badge"; +import Badge from './Badge'; -export default function Confidential({...props}) { - return ( - CONFIDENTIAL - ) +export default function Confidential({ ...props }) { + return ( + CONFIDENTIAL + ); } diff --git a/src/components/ContactBox.js b/src/components/ContactBox.js index 12bce14..2dbb444 100644 --- a/src/components/ContactBox.js +++ b/src/components/ContactBox.js @@ -1,16 +1,17 @@ import React from 'react'; -import * as Icon from '@codeday/topocons/Icon'; +import { DevicePhone, Email, IdCard } from '@codeday/topocons'; import InfoBox from './InfoBox'; export default function ContactBox({ - name, email, phone, children, ...props - }) { - return ( - - {name}
- {email}
- {phone}{children ?
: null} - {children} -
- ); + name, email, phone, children, ...props +}) { + return ( + + {name}
+ {email}
+ {phone} + {children ?
: null} + {children} +
+ ); } diff --git a/src/components/DaysUntilEvent.js b/src/components/DaysUntilEvent.js index f0405f4..3437188 100644 --- a/src/components/DaysUntilEvent.js +++ b/src/components/DaysUntilEvent.js @@ -1,30 +1,32 @@ import React from 'react'; -import {Text} from "@codeday/topo/Atom"; +import { Text } from '@codeday/topo/Atom'; import moment from 'moment-timezone'; import InfoBox from './InfoBox'; -function DayDisplay({ text, redText, children, ...props }) { - return ( - - {text}{text && redText && <> } - {redText && ( - - {redText} - - )} - - {children} - - ); +function DayDisplay({ + text, redText, children, ...props +}) { + return ( + + {text}{text && redText && <> } + {redText && ( + + {redText} + + )} + + {children} + + ); } -export default function DaysUntilEvent({event, ...props}) { - const now = moment().utc(false); - const eventStart = moment(event.startDate).utc(); - const daysUntil = Math.ceil(moment.duration(eventStart.diff(now)).as('days')); +export default function DaysUntilEvent({ event, ...props }) { + const now = moment().utc(false); + const eventStart = moment(event.startDate).utc(); + const daysUntil = Math.ceil(moment.duration(eventStart.diff(now)).as('days')); - if (daysUntil < 0) return ; - if (daysUntil === 0) return ; - if (daysUntil === 1) return - return + if (daysUntil < 0) return ; + if (daysUntil === 0) return ; + if (daysUntil === 1) return ; + return ; } diff --git a/src/components/DocsCallout.js b/src/components/DocsCallout.js index 53c2d29..acb20e5 100644 --- a/src/components/DocsCallout.js +++ b/src/components/DocsCallout.js @@ -1,9 +1,9 @@ import React from 'react'; import { Box, HStack } from '@codeday/topo/Atom'; -import {useColorModeValue} from "@codeday/topo/Theme"; -import { FileDoc } from '@codeday/topocons/Icon' +import { useColorModeValue } from '@codeday/topo/Theme'; +import { FileDoc } from '@codeday/topocons'; -export default function DocsCallout({children, ...props}) { +export default function DocsCallout({ children, ...props }) { return ( - - Sent to {template.sendTo} {template.when} {template.whenFrom} - - - {template.automatic? Automatic : Manual} - {template.sendParent? Sent to parents : null} - {template.marketing? Marketing : null } - {template.sendAfterEvent? Post-Event Email : null} - {template.sendText? Has SMS alternative : Not sent as SMS} - {template.sendInWorkHours? Only sent during work hours : null} - {template.sendLate? Sent Retroactively : null} - - - From: {template.fromName} ({template.fromEmail}) - Reply To: {template.replyTo} - Subject: {template.subject} -
- Body - {template.template} -
- {template.sendText? <>SMS: {template.textMsg}:null} -
- {children} - - ) +export default function EmailTemplate({ template, children, ...props }) { + return ( + + + Sent to {template.sendTo} {template.when} {template.whenFrom} + + + {template.automatic ? Automatic : Manual} + {template.sendParent ? Sent to parents : null} + {template.marketing ? Marketing : null } + {template.sendAfterEvent ? Post-Event Email : null} + {template.sendText ? Has SMS alternative : Not sent as SMS} + {template.sendInWorkHours ? Only sent during work hours : null} + {template.sendLate ? Sent Retroactively : null} + + + From: {template.fromName} ({template.fromEmail}) + Reply To: {template.replyTo} + Subject: {template.subject} +
+ Body + {template.template} +
+ {template.sendText ? <>SMS: {template.textMsg} : null} +
+ {children} +
+ ); } diff --git a/src/components/Event.js b/src/components/Event.js index 3e78956..3477875 100644 --- a/src/components/Event.js +++ b/src/components/Event.js @@ -1,30 +1,30 @@ -import React from 'react' -import {Box, Flex, Text} from "@codeday/topo/Atom"; +import React from 'react'; +import { Box, Flex, Text } from '@codeday/topo/Atom'; import { DateTime } from 'luxon'; -import InfoBox from "./InfoBox"; -import {Image} from '@chakra-ui/react'; +import { Image } from '@chakra-ui/react'; +import InfoBox from './InfoBox'; -export default function Event({event, ...props}) { - const now = DateTime.now(); - return ( - {event.name} - {event.eventGroup?.name}} - id={event.id} - as="a" - href={`/events/${event.id}`} - opacity={DateTime.fromISO(event.endDate) < now ? 0.5 : 1} - {...props} - > - - - - - - {event.displayDate} - {event.soldTickets + (event.soldTickets == 1 ? " ticket" : " tickets")} sold - {event.soldTickets > 0 && ({event.students} students {event.soldTickets - event.students} staff)} - - - - ) +export default function Event({ event, ...props }) { + const now = DateTime.now(); + return ( + {event.name} - {event.eventGroup?.name}} + id={event.id} + as="a" + href={`/events/${event.id}`} + opacity={DateTime.fromISO(event.endDate) < now ? 0.5 : 1} + {...props} + > + + + + + + {event.displayDate} + {event.soldTickets + (event.soldTickets == 1 ? ' ticket' : ' tickets')} sold + {event.soldTickets > 0 && ({event.students} students {event.soldTickets - event.students} staff)} + + + + ); } diff --git a/src/components/EventGroup.js b/src/components/EventGroup.js index 7494314..1f4bd15 100644 --- a/src/components/EventGroup.js +++ b/src/components/EventGroup.js @@ -1,15 +1,15 @@ import React from 'react'; -import {Box, Text} from "@codeday/topo/Atom"; +import { Box, Text } from '@codeday/topo/Atom'; import moment from 'moment'; -import InfoBox from "./InfoBox"; +import InfoBox from './InfoBox'; -export default function EventGroup({group, ...props}) { - return ( - - - {group.displayDate} - {group.events.length} Events - - - ); +export default function EventGroup({ group, ...props }) { + return ( + + + {group.displayDate} + {group.events.length} Events + + + ); } diff --git a/src/components/EventRestriction.js b/src/components/EventRestriction.js index c110cea..49fd31c 100644 --- a/src/components/EventRestriction.js +++ b/src/components/EventRestriction.js @@ -1,149 +1,157 @@ -import React, {useRef, useState} from 'react'; -import {Box, Button, Image, Link, Text} from "@codeday/topo/Atom"; -import InfoBox from "./InfoBox"; -import {DeleteEventRestrictionModal, UpdateEventRestrictionModal} from "./forms/EventRestriction"; -import {marked} from "marked"; +import React, { useRef, useState } from 'react'; +import { + Box, Button, Image, Link, Text, +} from '@codeday/topo/Atom'; +import { marked } from 'marked'; import DOMPurify from 'isomorphic-dompurify'; import ReactHtmlParser from 'react-html-parser'; -import Notes from "./forms/Notes"; -import {SetEventRestrictionNotesMutation} from "./forms/Notes.gql" -import {useSession} from "next-auth/react"; -import {useFetcher} from "../fetch"; -import {UploadEventRestrictionIconMutation} from "./forms/EventRestriction.gql"; -import Alert from "./Alert"; -import {UiUpload} from "@codeday/topocons/Icon"; -import {useToasts} from "@codeday/topo/utils"; +import { useSession } from 'next-auth/react'; +import { UiUpload } from '@codeday/topocons'; +import { useToasts } from '@codeday/topo/utils'; +import InfoBox from './InfoBox'; +import { DeleteEventRestrictionModal, UpdateEventRestrictionModal } from './forms/EventRestriction'; +import Notes from './forms/Notes'; +import { SetEventRestrictionNotesMutation } from './forms/Notes.gql'; +import { useFetcher } from '../fetch'; +import { UploadEventRestrictionIconMutation } from './forms/EventRestriction.gql'; +import Alert from './Alert'; -const WARN_FILE_SIZE = 1024 * 1024 * 5 -const MAX_FILE_SIZE = 1024 * 1024 * 125 -const MIME_IMAGE = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/svg+xml'] +const WARN_FILE_SIZE = 1024 * 1024 * 5; +const MAX_FILE_SIZE = 1024 * 1024 * 125; +const MIME_IMAGE = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/svg+xml']; function Highlight({ children }) { - return {children}; + return {children}; } function transform(node) { - if(node.type === "tag" && node.name === "strong") { - return {node.children[0].data} - } - if(node.type === "tag" && node.name === "a" && node.attribs.href) { - if(node.children[0].data.startsWith('btn ')) { - return - } - return {node.children[0].data} + if (node.type === 'tag' && node.name === 'strong') { + return {node.children[0].data}; + } + if (node.type === 'tag' && node.name === 'a' && node.attribs.href) { + if (node.children[0].data.startsWith('btn ')) { + return ; } + return {node.children[0].data}; + } } -export default function EventRestriction({eventRestriction, ...props}) { - const session = useSession(); - const fetch = useFetcher(session); - const uploaderRef = useRef(null); - const [logoUrl, setLogoUrl] = useState(eventRestriction.iconUri); - const [uploading, setUploading] = useState(false); - const { success, error, info } = useToasts(); +export default function EventRestriction({ eventRestriction, ...props }) { + const session = useSession(); + const fetch = useFetcher(session); + const uploaderRef = useRef(null); + const [logoUrl, setLogoUrl] = useState(eventRestriction.iconUri); + const [uploading, setUploading] = useState(false); + const { success, error, info } = useToasts(); - return ( - - - - } - > - - + + + +)} + > + + uploaderRef.current.click() - }/> - { - const file = e.target.files[0]; - if (!file) return; + } + /> + { + const file = e.target.files[0]; + if (!file) return; - let type = null; - if (MIME_IMAGE.includes(file.type)) type = 'IMAGE'; - if (!type) { - error('Only images are supported.'); - return; - } + let type = null; + if (MIME_IMAGE.includes(file.type)) type = 'IMAGE'; + if (!type) { + error('Only images are supported.'); + return; + } - if (file.size > MAX_FILE_SIZE) { - error(`You might have a problem uploading files larger than ${Math.floor(MAX_FILE_SIZE / (1024 * 1024))}MB`); - } + if (file.size > MAX_FILE_SIZE) { + error(`You might have a problem uploading files larger than ${Math.floor(MAX_FILE_SIZE / (1024 * 1024))}MB`); + } - var reader = new FileReader(); - reader.onload = function(el) { - setLogoUrl(el.target.result.iconUri) - } - reader.readAsDataURL(file); + const reader = new FileReader(); + reader.onload = function (el) { + setLogoUrl(el.target.result.iconUri); + }; + reader.readAsDataURL(file); - if (file.size > WARN_FILE_SIZE) { - info(`Your file is uploading, but at ${Math.floor(file.size / (1024 * 1024))}MB, it might take a while.`) - } else { - info(`Your file is uploading.`); - } - try { - setUploading(true); - const result = await fetch(UploadEventRestrictionIconMutation, { where: {id: eventRestriction.id}, file }) - success('Icon Uploaded!') - setLogoUrl(result.iconUri); - } catch (e) { - error(e.toString()) - } - setUploading(false) - }} - /> - {!eventRestriction.iconUri? <> - No Icon - - : null} - - {ReactHtmlParser(DOMPurify.sanitize(marked.parse(eventRestriction.title || '')), {transform})} - - - {ReactHtmlParser(DOMPurify.sanitize(marked.parse(eventRestriction.details || '')), {transform})} - - -
- -
- ); + if (file.size > WARN_FILE_SIZE) { + info(`Your file is uploading, but at ${Math.floor(file.size / (1024 * 1024))}MB, it might take a while.`); + } else { + info(`Your file is uploading.`); + } + try { + setUploading(true); + const result = await fetch(UploadEventRestrictionIconMutation, { where: { id: eventRestriction.id }, file }); + success('Icon Uploaded!'); + setLogoUrl(result.iconUri); + } catch (e) { + error(e.toString()); + } + setUploading(false); + }} + /> + {!eventRestriction.iconUri ? ( + <> + No Icon + + + ) : null} + + {ReactHtmlParser(DOMPurify.sanitize(marked.parse(eventRestriction.title || '')), { transform })} + + + {ReactHtmlParser(DOMPurify.sanitize(marked.parse(eventRestriction.details || '')), { transform })} + +
+
+ + + ); } -export function EventRestrictionPreview({eventRestriction, ...props}) { - return ( - - - - {ReactHtmlParser(DOMPurify.sanitize(marked.parse(eventRestriction.title || '')), {transform})} - - - {ReactHtmlParser(DOMPurify.sanitize(marked.parse(eventRestriction.details || '')), {transform})} - - - ); +export function EventRestrictionPreview({ eventRestriction, ...props }) { + return ( + + + + {ReactHtmlParser(DOMPurify.sanitize(marked.parse(eventRestriction.title || '')), { transform })} + + + {ReactHtmlParser(DOMPurify.sanitize(marked.parse(eventRestriction.details || '')), { transform })} + + + ); } diff --git a/src/components/EventRestrictionBox.js b/src/components/EventRestrictionBox.js index 3902044..18d7289 100644 --- a/src/components/EventRestrictionBox.js +++ b/src/components/EventRestrictionBox.js @@ -1,20 +1,21 @@ import React from 'react'; -import InfoBox from "./InfoBox"; -import {InfoAlert} from "./Alert"; -import {Box} from "@codeday/topo/Atom"; +import { Box } from '@codeday/topo/Atom'; +import InfoBox from './InfoBox'; +import { InfoAlert } from './Alert'; -export default function EventRestrictionBox({restrictions, children, ...props}) { - return ( - - - {restrictions.length > 0? -
    - {restrictions.map((r) =>
  • {r.name}
  • )} -
: - No Event restrictions - } -
- {children} -
- ) +export default function EventRestrictionBox({ restrictions, children, ...props }) { + return ( + + + {restrictions.length > 0 + ? ( +
    + {restrictions.map((r) =>
  • {r.name}
  • )} +
+ ) + : No Event restrictions} +
+ {children} +
+ ); } diff --git a/src/components/InfoBox.js b/src/components/InfoBox.js index 3edc07f..248d477 100644 --- a/src/components/InfoBox.js +++ b/src/components/InfoBox.js @@ -1,37 +1,39 @@ import React from 'react'; -import {Box, Flex, Text} from '@codeday/topo/Atom'; -import {useColorModeValue} from "@codeday/topo/Theme"; +import { Box, Flex, Text } from '@codeday/topo/Atom'; +import { useColorModeValue } from '@codeday/topo/Theme'; -export default function InfoBox({children, heading, subHeading, headingSize, buttons, nested, ...props}) { - return ( +export default function InfoBox({ + children, heading, subHeading, headingSize, buttons, nested, ...props +}) { + return ( + + {heading && ( + + + {heading} + {buttons} + + {subHeading && {subHeading}} + + )} - {heading && ( - - - {heading} - {buttons} - - {subHeading && {subHeading}} - - )} - - {children} - + {children} - ); + + ); } diff --git a/src/components/Kbd.js b/src/components/Kbd.js index 4f7182a..9fa264c 100644 --- a/src/components/Kbd.js +++ b/src/components/Kbd.js @@ -1,7 +1,6 @@ -import React from 'react' -import {Box} from '@codeday/topo/Atom'; -import { useColorModeValue } from '@codeday/topo/Theme' - +import React from 'react'; +import { Box } from '@codeday/topo/Atom'; +import { useColorModeValue } from '@codeday/topo/Theme'; // I was too lazy to update topo and export this so just made one myself export default function Kbd({ children, ...props }) { @@ -21,5 +20,5 @@ export default function Kbd({ children, ...props }) { > {children}
- ) + ); } diff --git a/src/components/LinkEventRestrictionsModal.js b/src/components/LinkEventRestrictionsModal.js index 01b02ee..d631711 100644 --- a/src/components/LinkEventRestrictionsModal.js +++ b/src/components/LinkEventRestrictionsModal.js @@ -1,83 +1,84 @@ -import React, {useState} from 'react'; -import {useRouter} from "next/router"; -import {Box, Button, Checkbox, Heading, Text} from "@codeday/topo/Atom"; -import * as Icon from "@codeday/topocons/Icon"; -import {Modal} from "react-responsive-modal"; -import {print} from "graphql"; -import {UpdateEventRestrictionsMutation} from "./LinkEventRestrictionsModal.gql" -import {useToasts} from "@codeday/topo/utils"; -import {useSession} from "next-auth/react"; -import {useFetcher} from "../fetch"; -import {useColorModeValue} from "@codeday/topo/Theme"; +import React, { useState } from 'react'; +import { useRouter } from 'next/router'; +import { + Box, Button, Checkbox, Heading, Text, +} from '@codeday/topo/Atom'; +import { UiEdit } from '@codeday/topocons'; +import { Modal } from 'react-responsive-modal'; +import { print } from 'graphql'; +import { useToasts } from '@codeday/topo/utils'; +import { useSession } from 'next-auth/react'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { useFetcher } from '../fetch'; +import { UpdateEventRestrictionsMutation } from './LinkEventRestrictionsModal.gql'; -export default function LinkEventRestrictionsModal({event, restrictions, requiredRestrictions, children, ...props}) { - const [open, setOpen] = useState(false); - const [loading, setLoading] = useState(false) - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const {success, error} = useToasts(); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [formData, setFormData] = useState(restrictions.reduce((prev, curr) => { - return { - ...prev, - [curr.id]: ( - (event.cmsEventRestrictions || []).filter(restriction => restriction.id === curr.id).length > 0 - && !((requiredRestrictions || []).filter(restriction => restriction.id === curr.id).length > 0) - ), - }}, {})) +export default function LinkEventRestrictionsModal({ + event, restrictions, requiredRestrictions, children, ...props +}) { + const [open, setOpen] = useState(false); + const [loading, setLoading] = useState(false); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const { success, error } = useToasts(); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [formData, setFormData] = useState(restrictions.reduce((prev, curr) => ({ + ...prev, + [curr.id]: ( + (event.cmsEventRestrictions || []).filter((restriction) => restriction.id === curr.id).length > 0 + && (requiredRestrictions || []).filter((restriction) => restriction.id === curr.id).length <= 0 + ), + }), {})); - const router = useRouter(); - return ( - - - - - Event Restrictions for {event.name} - - (Red checkmarks are required for your location and cannot be disabled.) - {restrictions.map((r) => ( - rq.id === r.id).length > 0} - isRequired={requiredRestrictions.filter(rq => rq.id === r.id).length > 0} - onChange={(e) => {setFormData({...formData, [r.id]:!formData[r.id]})}} - disabled={requiredRestrictions.filter(rq => rq.id === r.id).length > 0} - colorScheme={requiredRestrictions.filter(rq => rq.id === r.id).length > 0 ? 'red' : 'blue'} - > - {r.name} - - ) - )} - - - - ) + const router = useRouter(); + return ( + + + + + Event Restrictions for {event.name} + + (Red checkmarks are required for your location and cannot be disabled.) + {restrictions.map((r) => ( + rq.id === r.id).length > 0} + isRequired={requiredRestrictions.filter((rq) => rq.id === r.id).length > 0} + onChange={(e) => { setFormData({ ...formData, [r.id]: !formData[r.id] }); }} + disabled={requiredRestrictions.filter((rq) => rq.id === r.id).length > 0} + colorScheme={requiredRestrictions.filter((rq) => rq.id === r.id).length > 0 ? 'red' : 'blue'} + > + {r.name} + + ))} + + + + ); } diff --git a/src/components/MetadataBox.js b/src/components/MetadataBox.js index 90c08cf..42b1744 100644 --- a/src/components/MetadataBox.js +++ b/src/components/MetadataBox.js @@ -1,12 +1,16 @@ -import { Box, List, Text, ListItem } from '@codeday/topo/Atom'; -import InfoBox from "./InfoBox"; +import { + Box, List, Text, ListItem, +} from '@codeday/topo/Atom'; +import InfoBox from './InfoBox'; function MetadataItem({ mKey, value, ...props }) { - if (typeof value === 'undefined' || value === null) return ( - + if (typeof value === 'undefined' || value === null) { + return ( + null - - ); + + ); + } return ( {mKey && {mKey}: } @@ -15,24 +19,22 @@ function MetadataItem({ mKey, value, ...props }) { {Object.keys(value).map((k) => )} - ) : {value} - } + ) : {value}} ); } export default function MetadataBox({ metadata, children, ...props }) { - return ( - - - - - {children ? children : ( - - Reach out to your CodeDay staff contact if you need to make changes to metadata. - - )} - - ); + return ( + + + + + {children || ( + + Reach out to your CodeDay staff contact if you need to make changes to metadata. + + )} + + ); } - diff --git a/src/components/Opossum.js b/src/components/Opossum.js index 0bab3a0..8f29d08 100644 --- a/src/components/Opossum.js +++ b/src/components/Opossum.js @@ -1,7 +1,7 @@ -import * as THREE from "three"; -import {useEffect} from "react"; -import {OrbitControls} from "three/examples/jsm/controls/OrbitControls"; -import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader"; +import * as THREE from 'three'; +import { useEffect } from 'react'; +import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; function Opossum({ height, width }) { // const [renderer, setRenderer] = useState(); @@ -13,11 +13,11 @@ function Opossum({ height, width }) { 75, window.innerWidth / (window.innerHeight / 2), 0.1, - 1000 + 1000, ); const renderer = new THREE.WebGL1Renderer({ - canvas: document.querySelector("#bg"), + canvas: document.querySelector('#bg'), alpha: true, }); @@ -50,7 +50,7 @@ function Opossum({ height, width }) { let opossumObj; - loader.load("/Low_poly_opossum.glb", function (gltf) { + loader.load('/Low_poly_opossum.glb', (gltf) => { gltf.scene.traverse((node) => { if (!node.isMesh) return; node.material.wireframe = true; @@ -69,7 +69,7 @@ function Opossum({ height, width }) { renderer.render(scene, camera); }; - window.addEventListener("resize", resizeWindow); + window.addEventListener('resize', resizeWindow); function animate() { requestAnimationFrame(animate); @@ -88,7 +88,7 @@ function Opossum({ height, width }) { animate(); }, []); - return ; + return ; } export default Opossum; diff --git a/src/components/Page.js b/src/components/Page.js index 73c5f7b..54226e9 100644 --- a/src/components/Page.js +++ b/src/components/Page.js @@ -1,76 +1,87 @@ import React, { useEffect, useRef, useState } from 'react'; -import {Box, Button, Clear, Heading, Skelly, Spinner, Link} from '@codeday/topo/Atom'; -import {Content} from '@codeday/topo/Molecule'; -import {Header, Menu, SiteLogo, Footer, CustomLinks} from '@codeday/topo/Organism'; -import {DefaultSeo} from 'next-seo'; -import {signIn, signOut, useSession} from 'next-auth/react'; +import { + Box, Button, Clear, Heading, Skelly, Spinner, Link, +} from '@codeday/topo/Atom'; +import { Content } from '@codeday/topo/Molecule'; +import { + Header, Menu, SiteLogo, Footer, CustomLinks, +} from '@codeday/topo/Organism'; +import { DefaultSeo } from 'next-seo'; +import { signIn, signOut, useSession } from 'next-auth/react'; import HeadwayWidget from '@headwayapp/react-widget'; export default function Page({ - children, title, slug, ...props - }) { - const { data: session, status } = useSession(); - const loading = status === 'loading'; + children, title, slug, ...props +}) { + const { data: session, status } = useSession(); + const loading = status === 'loading'; - if (!session) { - return ( - -
- - - - - -
- - {loading ? : ( - <> - Log in with your CodeDay Account to continue - - - )} - -
- ); - } - const menuItems = ( - - - - - ); + if (!session) { return ( - <> - - -
- - - - -
- -
-
- - {loading ? : menuItems} - -
- - {children} - -
- - Events - API Token - -
-
- + +
+ + + + + +
+ + {loading ? : ( + <> + Log in with your CodeDay Account to continue + + + )} + +
); + } + const menuItems = ( + + + + + ); + return ( + <> + + +
+ + + + +
+ +
+
+ + {loading ? : menuItems} + +
+ + {children} + +
+ + Events + API Token + +
+
+ + ); } diff --git a/src/components/PromoCodeBox.js b/src/components/PromoCodeBox.js index c2e5d16..f341cef 100644 --- a/src/components/PromoCodeBox.js +++ b/src/components/PromoCodeBox.js @@ -1,21 +1,21 @@ import React from 'react'; -import InfoBox from "./InfoBox"; +import InfoBox from './InfoBox'; -export default function PromoCodeBox({promoCode, children, ...props}) { - return ( - - {promoCode.type === 'PERCENT' && promoCode.amount === 100 && promoCode.uses === 1 ? ( - <> - Scholarship
- {promoCode.usesRemaining > 0 ? 'Not used' : 'Used'} - - ) : ( - <> - {promoCode.type === 'SUBTRACT' ? '$' : ''}{promoCode.amount}{promoCode.type === 'PERCENT' ? '%' : ''} off
- {promoCode.usesCount}/{promoCode.uses || <>∞} uses - {promoCode.usesRemaining? ` (${promoCode.usesRemaining} left)`: null} - - )} -
- ) +export default function PromoCodeBox({ promoCode, children, ...props }) { + return ( + + {promoCode.type === 'PERCENT' && promoCode.amount === 100 && promoCode.uses === 1 ? ( + <> + Scholarship
+ {promoCode.usesRemaining > 0 ? 'Not used' : 'Used'} + + ) : ( + <> + {promoCode.type === 'SUBTRACT' ? '$' : ''}{promoCode.amount}{promoCode.type === 'PERCENT' ? '%' : ''} off
+ {promoCode.usesCount}/{promoCode.uses || <>∞} uses + {promoCode.usesRemaining ? ` (${promoCode.usesRemaining} left)` : null} + + )} +
+ ); } diff --git a/src/components/RegistrationGraph.js b/src/components/RegistrationGraph.js index a84a737..bb9b38f 100644 --- a/src/components/RegistrationGraph.js +++ b/src/components/RegistrationGraph.js @@ -1,77 +1,82 @@ import React from 'react'; import moment from 'moment'; -import {Button, Box, Heading, Text} from '@codeday/topo/Atom'; -import InfoBox from './InfoBox'; -import {Eye} from '@codeday/topocons/Icon'; +import { + Button, Box, Heading, Text, +} from '@codeday/topo/Atom'; +import { Eye } from '@codeday/topocons'; import { AspectRatio } from '@chakra-ui/react'; import { SizeMe } from 'react-sizeme'; -import { Area, AreaChart, XAxis, YAxis, ReferenceLine } from 'recharts'; +import { + Area, AreaChart, XAxis, YAxis, ReferenceLine, +} from 'recharts'; +import InfoBox from './InfoBox'; export default function RegistrationGraph({ event, children, ...props }) { - const now = moment.min(moment(), moment(event.endDate)); - const DAYS = 30; - const graphStart = now.clone().subtract(DAYS, 'days'); - const data = []; - const ticketsWithDate = event.tickets.map((e) => ({ ...e, createdAt: moment(e.createdAt) })); + const now = moment.min(moment(), moment(event.endDate)); + const DAYS = 30; + const graphStart = now.clone().subtract(DAYS, 'days'); + const data = []; + const ticketsWithDate = event.tickets.map((e) => ({ ...e, createdAt: moment(e.createdAt) })); - for (let current = graphStart.clone(); current < now; current = current.add({ day: 1 })) { - data.push({ - x: -1 * Math.floor(now.diff(current, 'days')), - y: ticketsWithDate.filter(t => t.createdAt < current).length, - }); - } - return ( - - {event.tickets.length} Registrations - {event.soldTickets} students; {event.tickets.length - event.soldTickets} staff - {children} - {event.soldTickets > 0 && ( - {({ size }) => !(size.width && size.width > 0) ?
: ( - - - - - - - - - - - - {event.venue?.capacity && event.tickets.length > event.venue.capacity && ( - ( - {event.venue.capacity} cap - )} - strokeDasharray="3 3" - /> - )} - - - )}
- )} - {event.interestedEmails.length} pre-registrations -
- ); + for (let current = graphStart.clone(); current < now; current = current.add({ day: 1 })) { + data.push({ + x: -1 * Math.floor(now.diff(current, 'days')), + y: ticketsWithDate.filter((t) => t.createdAt < current).length, + }); + } + return ( + + {event.tickets.length} Registrations + {event.soldTickets} students; {event.tickets.length - event.soldTickets} staff + {children} + {event.soldTickets > 0 && ( + {({ size }) => (!(size.width && size.width > 0) ?
: ( + + + + + + + + + + + + {event.venue?.capacity && event.tickets.length > event.venue.capacity && ( + ( + {event.venue.capacity} cap + )} + strokeDasharray="3 3" + /> + )} + + + ))} + + )} + {event.interestedEmails.length} pre-registrations + + ); } diff --git a/src/components/RegistrationsToggleWithChecklist.js b/src/components/RegistrationsToggleWithChecklist.js index aeeaf02..99b5e32 100644 --- a/src/components/RegistrationsToggleWithChecklist.js +++ b/src/components/RegistrationsToggleWithChecklist.js @@ -1,120 +1,119 @@ -import React, {useState} from "react"; -import {Box, Switch, Text, Checkbox, Stack, Tooltip, Divider} from "@codeday/topo/Atom" -import { UiInfo } from "@codeday/topocons/Icon" -import Alert, {WarningAlert} from "./Alert" -import InfoBox from "./InfoBox" -import {useFetcher} from "../fetch"; -import {useToasts} from "@codeday/topo/utils" -import {RegistrationsToggleMutation} from "./RegistrationsToggleWithChecklist.gql" -import {useRouter} from "next/router"; -import {useSession} from "next-auth/react"; +import React, { useState } from 'react'; +import { + Box, Switch, Text, Checkbox, Stack, Tooltip, Divider, +} from '@codeday/topo/Atom'; +import { UiInfo } from '@codeday/topocons'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useSession } from 'next-auth/react'; +import Alert, { WarningAlert } from './Alert'; +import InfoBox from './InfoBox'; +import { useFetcher } from '../fetch'; +import { RegistrationsToggleMutation } from './RegistrationsToggleWithChecklist.gql'; -function CheckListItem({item, nested=false}) { - if(item.hide) return <> - if (!item.checklist || !item.check || !item.checklist.map(c => c.check).includes(false)) { +function CheckListItem({ item, nested = false }) { + if (item.hide) return <>; + if (!item.checklist || !item.check || !item.checklist.map((c) => c.check).includes(false)) { return ( - {item.name} { item.description ? : null } - ) + {item.name} { item.description ? : null } + + ); } return ( <> {item.name} - {item.checklist.map(i => )} + {item.checklist.map((i) => )} - ) + ); } - - -export default function RegistrationsToggleWithChecklist({event, children, ...props}) { +export default function RegistrationsToggleWithChecklist({ event, children, ...props }) { const checklist = [ { - name: "Find a venue", + name: 'Find a venue', check: Boolean(event.venue), requiredToOpen: true, checklist: [ { - name: "Enter Address", - check: Boolean(event.venue?.address) + name: 'Enter Address', + check: Boolean(event.venue?.address), }, { - name: "Enter Capacity", - check: Boolean(event.venue?.capacity > 0) + name: 'Enter Capacity', + check: Boolean(event.venue?.capacity > 0), }, { - name: "Enter Contact Details", - check: Boolean(event.venue?.contactName && - (event.venue?.contactEmail || - event.venue?.contactPhone)) + name: 'Enter Contact Details', + check: Boolean(event.venue?.contactName + && (event.venue?.contactEmail + || event.venue?.contactPhone)), }, { - name: "Enter Map Link", - check: Boolean(event.venue?.mapLink) - } - ] + name: 'Enter Map Link', + check: Boolean(event.venue?.mapLink), + }, + ], }, { - name: "Configure event restrictions", + name: 'Configure event restrictions', hide: Boolean(!event.venue), - check: Boolean(event.eventRestrictions?.length > 0) + check: Boolean(event.eventRestrictions?.length > 0), }, { - name: "Create initial schedule", + name: 'Create initial schedule', hide: Boolean(!event.venue), - description: "This does not have to be the entire final schedule for your event! However, at a minimum, publish events for the start, end, and meals.", - check: Boolean(event.schedule.filter((item) => { - return item.finalized - }).length > 0) + description: 'This does not have to be the entire final schedule for your event! However, at a minimum, publish events for the start, end, and meals.', + check: Boolean(event.schedule.filter((item) => item.finalized).length > 0), }, { - name: "Open Registrations", - check: Boolean(event.registrationsOpen) + name: 'Open Registrations', + check: Boolean(event.registrationsOpen), }, { - name: "Promote Event", + name: 'Promote Event', check: Boolean(event.registrationsOpen), checklist: [ { - name: "Create a promo code", - description: "Very few CodeDay attendees end up paying full price, and this is 100% intended! We recommend creating different promo codes for different schools/groups/etc you reach out to, this helps them feel special, as well as helps you track the most effective outreach methods!", - check: Boolean(event.promoCodes.length > 0) + name: 'Create a promo code', + description: 'Very few CodeDay attendees end up paying full price, and this is 100% intended! We recommend creating different promo codes for different schools/groups/etc you reach out to, this helps them feel special, as well as helps you track the most effective outreach methods!', + check: Boolean(event.promoCodes.length > 0), }, { - name: "Your first registration!", - check: Boolean(event.studentRegistrations.length > 0) + name: 'Your first registration!', + check: Boolean(event.studentRegistrations.length > 0), }, { - name: "50% of capacity sold out!", - check: Boolean(event.studentRegistrations.length > (event.venue?.capacity / 2)) + name: '50% of capacity sold out!', + check: Boolean(event.studentRegistrations.length > (event.venue?.capacity / 2)), }, { - name: "100% of capacity sold out - wow!", - check: Boolean(event.allRegistrations.length >= event.venue?.capacity ) - } + name: '100% of capacity sold out - wow!', + check: Boolean(event.allRegistrations.length >= event.venue?.capacity), + }, - ] - } - ] - const disabled = Boolean(checklist.filter(c => c.requiredToOpen).map(c => c.check).includes(false)) + ], + }, + ]; + const disabled = Boolean(checklist.filter((c) => c.requiredToOpen).map((c) => c.check).includes(false)); const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); + const { success, error } = useToasts(); const { data: session } = useSession(); const fetch = useFetcher(session); const router = useRouter(); @@ -125,9 +124,9 @@ export default function RegistrationsToggleWithChecklist({event, children, ...pr {event.tickets.length >= event.venue?.capacity ? ( sold out. ) : ( - event.registrationsOpen ? - open. : - closed. + event.registrationsOpen + ? open. + : closed. )} { - setLoading(true) + setLoading(true); try { await fetch(RegistrationsToggleMutation, { - eventWhere: {id: event.id}, - data: e.target.checked - }) + eventWhere: { id: event.id }, + data: e.target.checked, + }); await router.replace(router.asPath); // kind of clunky solution to refresh serverSideProps after update; https://www.joshwcomeau.com/nextjs/refreshing-server-side-props/ - success(`Registrations ${e.target.checked ? "opened" : "closed"}`) + success(`Registrations ${e.target.checked ? 'opened' : 'closed'}`); } catch (ex) { - error(ex.toString()) + error(ex.toString()); } - setLoading(false) + setLoading(false); }} /> {event.registrationsOpen && ( @@ -158,9 +157,9 @@ export default function RegistrationsToggleWithChecklist({event, children, ...pr )} - { - checklist.map(item => ) + { + checklist.map((item) => ) } - ) + ); } diff --git a/src/components/ScheduleBox.js b/src/components/ScheduleBox.js index 99ac742..b86be82 100644 --- a/src/components/ScheduleBox.js +++ b/src/components/ScheduleBox.js @@ -1,23 +1,23 @@ import React from 'react'; -import {Box, Heading} from "@codeday/topo/Atom"; +import { Box, Heading } from '@codeday/topo/Atom'; import InfoBox from './InfoBox'; -export default function ({schedule, children, ...props}) { - const finalizedExternalEvents = schedule.filter((val) => val.finalized && !val.internal); - const nonfinalizedExternalEvents = schedule.filter((val) => !val.finalized && !val.internal); - const internalEvents = schedule.filter((val) => val.internal); - return ( - - - {finalizedExternalEvents.length} Published Events - - - {nonfinalizedExternalEvents.length} Unpublished Events - - - {internalEvents.length} Internal Events - - {children} - - ); +export default function ({ schedule, children, ...props }) { + const finalizedExternalEvents = schedule.filter((val) => val.finalized && !val.internal); + const nonfinalizedExternalEvents = schedule.filter((val) => !val.finalized && !val.internal); + const internalEvents = schedule.filter((val) => val.internal); + return ( + + + {finalizedExternalEvents.length} Published Events + + + {nonfinalizedExternalEvents.length} Unpublished Events + + + {internalEvents.length} Internal Events + + {children} + + ); } diff --git a/src/components/SponsorBox.js b/src/components/SponsorBox.js index 849d0e3..12ed5ca 100644 --- a/src/components/SponsorBox.js +++ b/src/components/SponsorBox.js @@ -1,156 +1,164 @@ -import React, {useRef, useState} from 'react'; -import {Box, Button, Image} from "@codeday/topo/Atom"; -import {useToasts} from '@codeday/topo/utils'; +import React, { useRef, useState } from 'react'; +import { Box, Button, Image } from '@codeday/topo/Atom'; +import { useToasts } from '@codeday/topo/utils'; import Masonry from 'react-responsive-masonry'; +import { useSession } from 'next-auth/react'; +import { UiUpload } from '@codeday/topocons'; import InfoBox from './InfoBox'; -import {DeleteSponsorModal, UpdateSponsorModal} from './forms/Sponsor'; +import { DeleteSponsorModal, UpdateSponsorModal } from './forms/Sponsor'; import ContactBox from './ContactBox'; -import {SetSponsorNotesMutation} from './forms/Notes.gql'; -import {UploadSponsorDarkLogoMutation, UploadSponsorLogoMutation} from './forms/Sponsor.gql' +import { SetSponsorNotesMutation } from './forms/Notes.gql'; +import { UploadSponsorDarkLogoMutation, UploadSponsorLogoMutation } from './forms/Sponsor.gql'; import Notes from './forms/Notes'; -import {useSession} from "next-auth/react"; -import {useFetcher} from "../fetch"; -import Alert, {InfoAlert} from "./Alert"; -import {UiUpload} from "@codeday/topocons/Icon" +import { useFetcher } from '../fetch'; +import Alert, { InfoAlert } from './Alert'; -const WARN_FILE_SIZE = 1024 * 1024 * 5 -const MAX_FILE_SIZE = 1024 * 1024 * 125 -const MIME_IMAGE = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'] +const WARN_FILE_SIZE = 1024 * 1024 * 5; +const MAX_FILE_SIZE = 1024 * 1024 * 125; +const MIME_IMAGE = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif']; -export default function SponsorBox({sponsor, currencySymbol, children, ...props}) { - const logoUploaderRef = useRef(null); - const darkLogoUploaderRef = useRef(null); - const [logoUrl, setLogoUrl] = useState(sponsor.logoImageUri); - const [darkLogoUrl, setDarkLogoUrl] = useState(sponsor.darkLogoImageUri); - const [uploading, setUploading] = useState(false); - const { success, error, info } = useToasts(); - const session = useSession(); - const fetch = useFetcher(session); +export default function SponsorBox({ + sponsor, currencySymbol, children, ...props +}) { + const logoUploaderRef = useRef(null); + const darkLogoUploaderRef = useRef(null); + const [logoUrl, setLogoUrl] = useState(sponsor.logoImageUri); + const [darkLogoUrl, setDarkLogoUrl] = useState(sponsor.darkLogoImageUri); + const [uploading, setUploading] = useState(false); + const { success, error, info } = useToasts(); + const session = useSession(); + const fetch = useFetcher(session); - return ( - - {sponsor.name} - + return ( + + {sponsor.name} + + )} - {...props} - > - - {sponsor.description} - - Amount: {currencySymbol || '$'}{sponsor.amount} -
- Perks: {sponsor.perks} -
- - - logoUploaderRef.current.click()} /> - { - const file = e.target.files[0]; - if (!file) return; + {...props} + > + + {sponsor.description} + + Amount: {currencySymbol || '$'}{sponsor.amount} +
+ Perks: {sponsor.perks} +
+ + + logoUploaderRef.current.click()} /> + { + const file = e.target.files[0]; + if (!file) return; - let type = null; - if (MIME_IMAGE.includes(file.type)) type = 'IMAGE'; - if (!type) { - error('Only images are supported.'); - return; - } + let type = null; + if (MIME_IMAGE.includes(file.type)) type = 'IMAGE'; + if (!type) { + error('Only images are supported.'); + return; + } - if (file.size > MAX_FILE_SIZE) { - error(`You might have a problem uploading files larger than ${Math.floor(MAX_FILE_SIZE / (1024 * 1024))}MB`); - } + if (file.size > MAX_FILE_SIZE) { + error(`You might have a problem uploading files larger than ${Math.floor(MAX_FILE_SIZE / (1024 * 1024))}MB`); + } - var reader = new FileReader(); - reader.onload = function(el) { - setLogoUrl(el.target.result.logoImageUri) - } - reader.readAsDataURL(file); + const reader = new FileReader(); + reader.onload = function (el) { + setLogoUrl(el.target.result.logoImageUri); + }; + reader.readAsDataURL(file); - if (file.size > WARN_FILE_SIZE) { - info(`Your file is uploading, but at ${Math.floor(file.size / (1024 * 1024))}MB, it might take a while.`) - } else { - info(`Your file is uploading.`); - } - try { - setUploading(true); - const result = await fetch(UploadSponsorLogoMutation, { where: {id: sponsor.id}, file }) - success('Logo Uploaded!') - setLogoUrl(result.logoImageUri); - } catch (e) { - error(e.toString()) - } - setUploading(false) - }} - /> - {!sponsor.logoImageUri? <> - No Sponsor Logo - - : null} - - - darkLogoUploaderRef.current.click()} /> - { - const file = e.target.files[0]; - if (!file) return; + if (file.size > WARN_FILE_SIZE) { + info(`Your file is uploading, but at ${Math.floor(file.size / (1024 * 1024))}MB, it might take a while.`); + } else { + info(`Your file is uploading.`); + } + try { + setUploading(true); + const result = await fetch(UploadSponsorLogoMutation, { where: { id: sponsor.id }, file }); + success('Logo Uploaded!'); + setLogoUrl(result.logoImageUri); + } catch (e) { + error(e.toString()); + } + setUploading(false); + }} + /> + {!sponsor.logoImageUri ? ( + <> + No Sponsor Logo + + + ) : null} + + + darkLogoUploaderRef.current.click()} /> + { + const file = e.target.files[0]; + if (!file) return; - let type = null; - if (MIME_IMAGE.includes(file.type)) type = 'IMAGE'; - if (!type) { - error('Only images are supported.'); - return; - } + let type = null; + if (MIME_IMAGE.includes(file.type)) type = 'IMAGE'; + if (!type) { + error('Only images are supported.'); + return; + } - if (file.size > MAX_FILE_SIZE) { - error(`You might have a problem uploading files larger than ${Math.floor(MAX_FILE_SIZE / (1024 * 1024))}MB`); - } + if (file.size > MAX_FILE_SIZE) { + error(`You might have a problem uploading files larger than ${Math.floor(MAX_FILE_SIZE / (1024 * 1024))}MB`); + } - var reader = new FileReader(); - reader.onload = function(el) { - setDarkLogoUrl(el.target.result.darkLogoImageUri) - } - reader.readAsDataURL(file); + const reader = new FileReader(); + reader.onload = function (el) { + setDarkLogoUrl(el.target.result.darkLogoImageUri); + }; + reader.readAsDataURL(file); - if (file.size > WARN_FILE_SIZE) { - info(`Your file is uploading, but at ${Math.floor(file.size / (1024 * 1024))}MB, it might take a while.`) - } else { - info(`Your file is uploading.`); - } - try { - setUploading(true); - const result = await fetch(UploadSponsorDarkLogoMutation, { where: {id: sponsor.id}, file }) - success('Logo Uploaded!') - setLogoUrl(result.darkLogoImageUri); - } catch (e) { - error(e.toString()) - } - setUploading(false) - }} - /> - {!sponsor.darkLogoImageUri? <> - No Dark Mode Sponsor Logo - - : null} - - -
- {children} + if (file.size > WARN_FILE_SIZE) { + info(`Your file is uploading, but at ${Math.floor(file.size / (1024 * 1024))}MB, it might take a while.`); + } else { + info(`Your file is uploading.`); + } + try { + setUploading(true); + const result = await fetch(UploadSponsorDarkLogoMutation, { where: { id: sponsor.id }, file }); + success('Logo Uploaded!'); + setLogoUrl(result.darkLogoImageUri); + } catch (e) { + error(e.toString()); + } + setUploading(false); + }} + /> + {!sponsor.darkLogoImageUri ? ( + <> + No Dark Mode Sponsor Logo + + + ) : null}
- ); + +
+ {children} +
+ ); } diff --git a/src/components/SponsorOverview.js b/src/components/SponsorOverview.js index 8f10cf3..d80f7d4 100644 --- a/src/components/SponsorOverview.js +++ b/src/components/SponsorOverview.js @@ -1,9 +1,11 @@ import React from 'react'; -import {Heading, Text, Link} from "@codeday/topo/Atom"; +import { Heading, Text, Link } from '@codeday/topo/Atom'; import InfoBox from './InfoBox'; -import DocsCallout from "./DocsCallout"; +import DocsCallout from './DocsCallout'; -export default function SponsorOverview({sponsors, children, currencySymbol, ...props}) { +export default function SponsorOverview({ + sponsors, children, currencySymbol, ...props +}) { let total = 0; sponsors.forEach((sponsor) => { total += sponsor.amount; @@ -12,12 +14,14 @@ export default function SponsorOverview({sponsors, children, currencySymbol, ... {currencySymbol || '$'}{total} raised from a total of {sponsors.length} sponsors - { sponsors.length === 0? - - Looking for help finding sponsors? Check out  - this page + { sponsors.length === 0 + ? ( + + Looking for help finding sponsors? Check out  + this page  in the CodeDay Organizer Guide! - + + ) : null} {children} diff --git a/src/components/Ticket.js b/src/components/Ticket.js index 7b96f40..4ba75f9 100644 --- a/src/components/Ticket.js +++ b/src/components/Ticket.js @@ -1,158 +1,161 @@ -import React, {useState} from 'react'; -import {print} from 'graphql'; -import {useSession} from 'next-auth/react'; -import {Box, Button, Text} from "@codeday/topo/Atom"; -import {useToasts} from '@codeday/topo/utils'; -import {checkin, checkout, sendWaiverReminder} from './Ticket.gql'; -import Badge from "./Badge"; -import Alert, {GoodAlert} from "./Alert"; -import {useFetcher} from '../fetch'; -import InfoBox from "./InfoBox"; -import * as Icon from "@codeday/topocons/Icon"; -import {useColorModeValue} from "@codeday/topo/Theme"; +import React, { useState } from 'react'; +import { print } from 'graphql'; +import { useSession } from 'next-auth/react'; +import { Box, Button, Text } from '@codeday/topo/Atom'; +import { useToasts } from '@codeday/topo/utils'; +import { Eye } from '@codeday/topocons'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { checkin, checkout, sendWaiverReminder } from './Ticket.gql'; +import Badge from './Badge'; +import Alert, { GoodAlert } from './Alert'; +import { useFetcher } from '../fetch'; +import InfoBox from './InfoBox'; -export default function Ticket({ticket, eventId, ...props}) { - const { data: session } = useSession(); +export default function Ticket({ ticket, eventId, ...props }) { + const { data: session } = useSession(); - const [loading, setLoading] = useState(false); - const [checkedIn, setCheckedIn] = useState(ticket.checkedIn); - const [checkedOut, setCheckedOut] = useState(ticket.checkedOut); - const {success, error} = useToasts(); - const fetch = useFetcher(session); - const checkAction = checkedIn && !checkedOut ? 'out' : 'in'; + const [loading, setLoading] = useState(false); + const [checkedIn, setCheckedIn] = useState(ticket.checkedIn); + const [checkedOut, setCheckedOut] = useState(ticket.checkedOut); + const { success, error } = useToasts(); + const fetch = useFetcher(session); + const checkAction = checkedIn && !checkedOut ? 'out' : 'in'; - return ( - - - - + return ( + + + + + )} + heading={( + <> + {ticket.lastName}, {ticket.firstName} + + +)} + {...props} + > + Age: {ticket.age} + {ticket.email && Email: {ticket.email}} + {ticket.phone && Phone: {ticket.phone}} + {ticket.whatsApp && WhatsApp: {ticket.whatsApp}} + {ticket.promoCode && Promo: {ticket.promoCode.code}} + {!ticket.waiverSigned && ( + + Waiver:{' '} + + + {ticket.waiverUrl && ( + + )} +
+
+ )} + {session && ( + - - {ticket.waiverUrl && ( - - )} -
- - )} - {session && ( - - )} - {ticket.waiverSigned ? Waiver : Waiver} - {ticket.vaccineVerified ? Vaccine : Vaccine} -
) + setLoading(false); + }} + > + Check {checkAction} + + )} + {ticket.waiverSigned ? Waiver : Waiver} + {ticket.vaccineVerified ? Vaccine : Vaccine} +
+ + ); } -export function TicketTypeBadge({ticket, ...props}) { - const ticketTypeStyles = { - STAFF: { - bg: "pink.200", - color: "pink.800" - }, - JUDGE: { - bg: "orange.200", - color: "orange.800" - }, - MENTOR: { - bg: "green.200", - color: "green.800" - }, - VIP: { - bg: "purple.200", - color: "purple.800" - }, - } - return ( - - {ticket.type} - - ) +export function TicketTypeBadge({ ticket, ...props }) { + const ticketTypeStyles = { + STAFF: { + bg: 'pink.200', + color: 'pink.800', + }, + JUDGE: { + bg: 'orange.200', + color: 'orange.800', + }, + MENTOR: { + bg: 'green.200', + color: 'green.800', + }, + VIP: { + bg: 'purple.200', + color: 'purple.800', + }, + }; + return ( + + {ticket.type} + + ); } diff --git a/src/components/TicketBox.js b/src/components/TicketBox.js index 7821c88..cb34556 100644 --- a/src/components/TicketBox.js +++ b/src/components/TicketBox.js @@ -1,28 +1,28 @@ import React from 'react'; -import InfoBox from "./InfoBox"; -import {Calendar, PaymentCash, PaymentDiscount} from "@codeday/topocons/Icon" -import Alert, {GoodAlert} from "./Alert"; -import moment from "moment-timezone"; -import {Text} from "@codeday/topo/Atom"; +import { Calendar, PaymentCash, PaymentDiscount } from '@codeday/topocons'; +import moment from 'moment-timezone'; +import { Text } from '@codeday/topo/Atom'; +import Alert, { GoodAlert } from './Alert'; +import InfoBox from './InfoBox'; export default function TicketBox({ event, children, ...props }) { - return ( - - - Early Bird Ticket Price: {event.region?.currencySymbol}{event.earlyBirdPrice} - - - Early Bird Deadline: {moment(event.earlyBirdCutoff).utc().format('LL')} - - {event.registrationsOpen? event.canEarlyBirdRegister ? Early Bird Active : Early Bird Inactive : null} - - Regular Ticket Price: {event.region?.currencySymbol}{event.ticketPrice} - - - Registration Deadline: {moment(event.registrationCutoff).utc().format('LL')} - - {event.registrationsOpen? event.canRegister ? Registrations Active : Registrations Inactive : null} - {children} - - ) + return ( + + + Early Bird Ticket Price: {event.region?.currencySymbol}{event.earlyBirdPrice} + + + Early Bird Deadline: {moment(event.earlyBirdCutoff).utc().format('LL')} + + {event.registrationsOpen ? event.canEarlyBirdRegister ? Early Bird Active : Early Bird Inactive : null} + + Regular Ticket Price: {event.region?.currencySymbol}{event.ticketPrice} + + + Registration Deadline: {moment(event.registrationCutoff).utc().format('LL')} + + {event.registrationsOpen ? event.canRegister ? Registrations Active : Registrations Inactive : null} + {children} + + ); } diff --git a/src/components/VenueInfo.js b/src/components/VenueInfo.js index 0c278c7..b0d7ba9 100644 --- a/src/components/VenueInfo.js +++ b/src/components/VenueInfo.js @@ -1,50 +1,54 @@ import React from 'react'; -import {Heading, Link, Text} from '@codeday/topo/Atom'; -import { FileDoc } from '@codeday/topocons/Icon' +import { Heading, Link, Text } from '@codeday/topo/Atom'; +import { FileDoc } from '@codeday/topocons'; import InfoBox from './InfoBox'; -import {DeleteVenueModal, UpdateVenueModal} from './forms/Venue'; +import { DeleteVenueModal, UpdateVenueModal } from './forms/Venue'; import ContactBox from './ContactBox'; -import DocsCallout from "./DocsCallout"; +import DocsCallout from './DocsCallout'; -export default function VenueInfo({venue, children, buttons, ...props}) { - if (!venue) return ( +export default function VenueInfo({ + venue, children, buttons, ...props +}) { + if (!venue) { + return ( - No venue... yet!
+ No venue... yet!
- - Click here + + Click here  to read tips on finding a venue in the CodeDay Organizer Guide! {children}
); - return ( - - + } + return ( + +   - - {buttons && <> {buttons}} - - } - {...props} - > - {venue.name} - - {venue.address} - - Capacity: {venue.capacity} - - {children} - - ); + + {buttons && <> {buttons}} + + )} + {...props} + > + {venue.name} + + {venue.address} + + Capacity: {venue.capacity} + + {children} + + ); } diff --git a/src/components/forms/EditSpecificMetadata.js b/src/components/forms/EditSpecificMetadata.js index b03ed77..44b45b5 100644 --- a/src/components/forms/EditSpecificMetadata.js +++ b/src/components/forms/EditSpecificMetadata.js @@ -1,68 +1,84 @@ -import React, {useState} from "react"; -import InfoBox from "../InfoBox"; -import {Box, Button, Text, Textarea as TextareaInput} from "@codeday/topo/Atom"; -import * as Icon from "@codeday/topocons/Icon" -import {useToasts} from "@codeday/topo/utils"; -import {useFetcher} from "../../fetch"; -import {useRouter} from "next/router"; -import {useSession} from "next-auth/react"; +import React, { useState } from 'react'; +import { + Box, Button, Text, Textarea as TextareaInput, +} from '@codeday/topo/Atom'; +import { UiEdit, UiOk, UiX } from '@codeday/topocons'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useSession } from 'next-auth/react'; +import { useFetcher } from '../../fetch'; +import InfoBox from '../InfoBox'; -export default function EditSpecificMetadata({ metadataKey, value, setMutation, updateId, displayKeyAs, description, placeholder, children, ...props}) { - const [editing, setEditing] = useState(false) - const [loading, setLoading] = useState(false) - const [tempValue, setTempValue] = useState(value) // Temporary value while the user is editing - const {success, error} = useToasts(); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const router = useRouter() +export default function EditSpecificMetadata({ + metadataKey, value, setMutation, updateId, displayKeyAs, description, placeholder, children, ...props +}) { + const [editing, setEditing] = useState(false); + const [loading, setLoading] = useState(false); + const [tempValue, setTempValue] = useState(value); // Temporary value while the user is editing + const { success, error } = useToasts(); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const router = useRouter(); - const okButton = - const trashButton = - const editButton = - const buttons = editing ? {okButton} {trashButton} : editButton; - return ( - - - {editing ? - setTempValue(e.target.value)} - placeholder={placeholder} - /> : - value?.split("\n").map((val) => {val})} - {children} - - - ) + const okButton = ( + + ); + const trashButton = ( + + ); + const editButton = ( + + ); + const buttons = editing ? {okButton} {trashButton} : editButton; + return ( + + + {editing + ? ( + setTempValue(e.target.value)} + placeholder={placeholder} + /> + ) + : value?.split('\n').map((val) => {val})} + {children} + + + ); } diff --git a/src/components/forms/EmailTemplate.js b/src/components/forms/EmailTemplate.js index 6d7074c..06034fa 100644 --- a/src/components/forms/EmailTemplate.js +++ b/src/components/forms/EmailTemplate.js @@ -1,299 +1,309 @@ -import React, {useState} from 'react'; -import Form from "@rjsf/chakra-ui"; -import {Box, Button, Heading, Text} from "@codeday/topo/Atom"; -import {Modal} from "react-responsive-modal"; +import React, { useState } from 'react'; +import Form from '@rjsf/chakra-ui'; +import { + Box, Button, Heading, Text, +} from '@codeday/topo/Atom'; +import { Modal } from 'react-responsive-modal'; import 'react-responsive-modal/styles.css'; -import * as Icon from "@codeday/topocons/Icon"; -import {useFetcher} from "../../fetch"; -import {useSession} from 'next-auth/react'; import { - CreateEmailTemplateMutation, - DeleteEmailTemplateMutation, - UpdateEmailTemplateMutation -} from "./EmailTemplate.gql"; -import {useToasts} from "@codeday/topo/utils"; -import {useRouter} from "next/router"; -import {ticketTypeEnum} from "./Ticket"; -import {useColorModeValue} from "@codeday/topo/Theme"; + UiAdd, UiEdit, UiTrash, UiX, +} from '@codeday/topocons'; +import { useSession } from 'next-auth/react'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { ticketTypeEnum } from './Ticket'; +import { + CreateEmailTemplateMutation, + DeleteEmailTemplateMutation, + UpdateEmailTemplateMutation, +} from './EmailTemplate.gql'; +import { useFetcher } from '../../fetch'; const schema = { - type: "object", - properties: { - name: { - title: 'Name (internal)', - type: 'string' - }, - automatic: { - title: 'Automatic?', - type: 'boolean', - default: false - - }, - fromName: { - title: 'From Name', - type: 'string', - default: 'John Peter' - }, - fromEmail: { - title: 'From Email', - type: 'string', - default: 'team@codeday.org' - }, - subject: { - title: 'Subject', - type: 'string', - }, - template: { - title: 'Email Text', - type: 'string' - }, - sendText: { - title: 'Send as text?', - type:'boolean', - default: false - - }, - textMsg: { - title: 'Text message', - type: 'string' - }, - sendTo: { - title: 'Send to', - type: 'string', - default: 'STUDENT', - anyOf: ticketTypeEnum - }, - when: { - type:'string', - title: 'Time offset', - }, - whenFrom: { - type: 'string', - title: 'Time offset source', - default: 'REGISTER', - anyOf: [ - { - type: 'string', - title: 'Registration', - enum: ['REGISTER'] - }, - { - type: 'string', - title: 'Event Start', - enum: ['EVENTSTART'] - }, - { - type: 'string', - title: 'Event End', - enum: ['EVENTEND'] - } - ] - }, - sendLate: { - title: 'Send Late?', - type: 'boolean', - default: false - }, - sendInWorkHours: { - title: 'Wait to send until work hours?', - type: 'boolean', - default: false - - }, - sendAfterEvent: { - title: 'Send after event?', - type: 'boolean', - default: false - - }, - sendParent: { - title: 'Send to parents?', - type: 'boolean', - default: false - - }, - marketing: { - title: 'Marketing email?', - type: 'boolean', - default: false - - }, - // extraFilters: { - // title: 'Extra filters (prisma `where`)', - // type: 'string' - // } - // Dropped feature to save dev time, unimplemented on backend. Might add at some point + type: 'object', + properties: { + name: { + title: 'Name (internal)', + type: 'string', }, - required: [ - "name", - "fromName", - "fromEmail", - "subject", - "sendTo", - "when", - "whenFrom", - "template", - ] -} + automatic: { + title: 'Automatic?', + type: 'boolean', + default: false, -const uiSchema = { + }, + fromName: { + title: 'From Name', + type: 'string', + default: 'John Peter', + }, + fromEmail: { + title: 'From Email', + type: 'string', + default: 'team@codeday.org', + }, + subject: { + title: 'Subject', + type: 'string', + }, template: { - 'ui:widget': 'textarea' + title: 'Email Text', + type: 'string', + }, + sendText: { + title: 'Send as text?', + type: 'boolean', + default: false, + + }, + textMsg: { + title: 'Text message', + type: 'string', + }, + sendTo: { + title: 'Send to', + type: 'string', + default: 'STUDENT', + anyOf: ticketTypeEnum, }, when: { - 'ui:help': 'Ex. -3d for 3 days before offset source time' + type: 'string', + title: 'Time offset', }, - sendText: { - 'ui:help': 'If we don\'t have a number on hand, an email will be sent instead' + whenFrom: { + type: 'string', + title: 'Time offset source', + default: 'REGISTER', + anyOf: [ + { + type: 'string', + title: 'Registration', + enum: ['REGISTER'], + }, + { + type: 'string', + title: 'Event Start', + enum: ['EVENTSTART'], + }, + { + type: 'string', + title: 'Event End', + enum: ['EVENTEND'], + }, + ], }, sendLate: { - 'ui:help': 'Only applies if time source is event start - if true, retroactively sends emails if people register after email sent to others' + title: 'Send Late?', + type: 'boolean', + default: false, + }, + sendInWorkHours: { + title: 'Wait to send until work hours?', + type: 'boolean', + default: false, + }, sendAfterEvent: { - 'ui:help': '**All** Email Templates without this option are barred from being sent if the event has ended' + title: 'Send after event?', + type: 'boolean', + default: false, + }, sendParent: { - 'ui:help': 'If selected, this email will only be sent to parents - to send to both, create two Email Templates' - } -} + title: 'Send to parents?', + type: 'boolean', + default: false, + + }, + marketing: { + title: 'Marketing email?', + type: 'boolean', + default: false, + + }, + // extraFilters: { + // title: 'Extra filters (prisma `where`)', + // type: 'string' + // } + // Dropped feature to save dev time, unimplemented on backend. Might add at some point + }, + required: [ + 'name', + 'fromName', + 'fromEmail', + 'subject', + 'sendTo', + 'when', + 'whenFrom', + 'template', + ], +}; + +const uiSchema = { + template: { + 'ui:widget': 'textarea', + }, + when: { + 'ui:help': 'Ex. -3d for 3 days before offset source time', + }, + sendText: { + 'ui:help': 'If we don\'t have a number on hand, an email will be sent instead', + }, + sendLate: { + 'ui:help': 'Only applies if time source is event start - if true, retroactively sends emails if people register after email sent to others', + }, + sendAfterEvent: { + 'ui:help': '**All** Email Templates without this option are barred from being sent if the event has ended', + }, + sendParent: { + 'ui:help': 'If selected, this email will only be sent to parents - to send to both, create two Email Templates', + }, +}; -export function CreateEmailTemplateModal({children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(/* if you need to set default values, do so here */); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function CreateEmailTemplateModal({ children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(/* if you need to set default values, do so here */); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Create EmailTemplate -
setFormData(data.formData)} - > - + + Create EmailTemplate + setFormData(data.formData)} + > + - -
-
- ) + }); + await router.replace(router.asPath); + success('EmailTemplate Created'); + onCloseModal(); + } catch (ex) { + error(ex.toString()); + } + setLoading(false); + }} + >Submit + + + + + ); } -export function UpdateEmailTemplateModal({emailtemplate, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(emailtemplate); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function UpdateEmailTemplateModal({ emailtemplate, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(emailtemplate); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - function formDataToUpdateInput(formData) { - const ret = {} - Object.keys(schema.properties).map((key) => { - if (formData[key] !== emailtemplate[key]) ret[key] = {set: formData[key]} - }) - return ret - } + function formDataToUpdateInput(formData) { + const ret = {}; + Object.keys(schema.properties).map((key) => { + if (formData[key] !== emailtemplate[key]) ret[key] = { set: formData[key] }; + }); + return ret; + } - return ( - - - -
setFormData(data.formData)} - > - -
-
-
- ) + return ( + + + +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function DeleteEmailTemplateModal({emailtemplate, children, ...props}) { - const [open, setOpen] = useState(false); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function DeleteEmailTemplateModal({ emailtemplate, children, ...props }) { + const [open, setOpen] = useState(false); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Remove EmailTemplate - Are you sure you want to delete this EmailTemplate? -
- There's no turning back!
- - -
-
- ) + return ( + + + + Remove EmailTemplate + Are you sure you want to delete this EmailTemplate? +
+ There's no turning back! +
+ + +
+
+ ); } diff --git a/src/components/forms/Event.js b/src/components/forms/Event.js index 258a838..f09f838 100644 --- a/src/components/forms/Event.js +++ b/src/components/forms/Event.js @@ -1,285 +1,288 @@ -import React, {useState} from 'react'; +import React, { useState } from 'react'; import Form from '@rjsf/chakra-ui'; - -import {Box, Button, Heading, Text} from "@codeday/topo/Atom"; -import {Modal} from 'react-responsive-modal'; +import { + Box, Button, Heading, Text, +} from '@codeday/topo/Atom'; +import { Modal } from 'react-responsive-modal'; import 'react-responsive-modal/styles.css'; -import * as Icon from '@codeday/topocons/Icon'; -import {useColorModeValue} from "@codeday/topo/Theme"; +import { + UiAdd, UiEdit, UiTrash, UiX, +} from '@codeday/topocons'; +import { useColorModeValue } from '@codeday/topo/Theme'; -import {useToasts, useTheme} from '@codeday/topo/utils'; -import {useRouter} from 'next/router'; +import { useToasts, useTheme } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; import moment from 'moment-timezone'; -import {useSession} from 'next-auth/react'; -import {CreateEventMutation, DeleteEventMutation, UpdateEventMutation} from './Event.gql'; -import {useFetcher} from '../../fetch'; -import {InfoAlert} from '../Alert'; +import { useSession } from 'next-auth/react'; +import { CreateEventMutation, DeleteEventMutation, UpdateEventMutation } from './Event.gql'; +import { useFetcher } from '../../fetch'; +import { InfoAlert } from '../Alert'; const schema = { - type: 'object', - properties: { - name: { - title: 'Name', - type: 'string', - }, - startDate: { - title: 'Start Date', - type: 'string', - format: 'date', - }, - endDate: { - title: 'End Date', - type: 'string', - format: 'date', - }, - ticketPrice: { - title: 'Ticket Price', - type: 'number', - multipleOf: 0.01, - }, - earlyBirdPrice: { - title: 'Early Bird Ticket Price', - type: 'number', - multipleOf: 0.01, - }, - groupPrice: { - type: "number", - multipleOf: 0.01, - title: "School Group Price" - }, - earlyBirdCutoff: { - title: 'Early Bird Registration Cutoff', - description: 'Usually set to a month before the event', - type: 'string', - format: 'date', - }, - registrationCutoff: { - title: 'Registration Cutoff', - type: 'string', - format: 'date', - }, - contentfulWebname: { - title: 'Contentful region ID', - type: 'string' - }, - managers: { - title: 'Regional Managers', - type: 'array', - uniqueItems: true, - items: { - type: 'string', - }, - }, - timezone: { - title: 'Timezone (IANA)', - type: 'string' - }, - majorityAge: { - title: 'Age of majority', - type: 'number', - default: 18 - }, - overnightMinAge: { - title: 'Minimum age to stay overnight', - type: 'number', - default: 14 - }, - minAge: { - title: 'Minimum age to register', - type: 'number', - default: 12 - }, - maxAge: { - title: 'Maximum age to register', - type: 'number', - default: 25 - }, - requiresPromoCode: { - type: 'boolean', - title: 'Requires Promo Code' - } + type: 'object', + properties: { + name: { + title: 'Name', + type: 'string', + }, + startDate: { + title: 'Start Date', + type: 'string', + format: 'date', + }, + endDate: { + title: 'End Date', + type: 'string', + format: 'date', + }, + ticketPrice: { + title: 'Ticket Price', + type: 'number', + multipleOf: 0.01, + }, + earlyBirdPrice: { + title: 'Early Bird Ticket Price', + type: 'number', + multipleOf: 0.01, + }, + groupPrice: { + type: 'number', + multipleOf: 0.01, + title: 'School Group Price', + }, + earlyBirdCutoff: { + title: 'Early Bird Registration Cutoff', + description: 'Usually set to a month before the event', + type: 'string', + format: 'date', + }, + registrationCutoff: { + title: 'Registration Cutoff', + type: 'string', + format: 'date', + }, + contentfulWebname: { + title: 'Contentful region ID', + type: 'string', + }, + managers: { + title: 'Regional Managers', + type: 'array', + uniqueItems: true, + items: { + type: 'string', + }, + }, + timezone: { + title: 'Timezone (IANA)', + type: 'string', }, + majorityAge: { + title: 'Age of majority', + type: 'number', + default: 18, + }, + overnightMinAge: { + title: 'Minimum age to stay overnight', + type: 'number', + default: 14, + }, + minAge: { + title: 'Minimum age to register', + type: 'number', + default: 12, + }, + maxAge: { + title: 'Maximum age to register', + type: 'number', + default: 25, + }, + requiresPromoCode: { + type: 'boolean', + title: 'Requires Promo Code', + }, + }, }; const uiSchema = { - managers: { - 'ui:options': { - orderable: false, - }, - 'ui:description': "(CodeDay Account usernames)", - "chakra": { - color: "blue.200" - }, + managers: { + 'ui:options': { + orderable: false, }, - requiresPromoCode: { - 'ui:help': 'Should people only be allowed to register if they have a promo code? (For instance if the event is invite-only) This should most of the time be false.' - } + 'ui:description': '(CodeDay Account usernames)', + chakra: { + color: 'blue.200', + }, + }, + requiresPromoCode: { + 'ui:help': 'Should people only be allowed to register if they have a promo code? (For instance if the event is invite-only) This should most of the time be false.', + }, }; -export function CreateEventModal({group, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState({ - startDate: moment(group.startDate).utc().format('YYYY-MM-DD'), - endDate: moment(group.endDate).utc().format('YYYY-MM-DD'), - ticketPrice: group.ticketPrice, - earlyBirdPrice: group.earlyBirdPrice, - groupPrice: group.groupPrice, - earlyBirdCutoff: moment(group.earlyBirdCutoff).utc().format('YYYY-MM-DD'), - registrationCutoff: moment(group.registrationCutoff).utc().format('YYYY-MM-DD'), - }); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function CreateEventModal({ group, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState({ + startDate: moment(group.startDate).utc().format('YYYY-MM-DD'), + endDate: moment(group.endDate).utc().format('YYYY-MM-DD'), + ticketPrice: group.ticketPrice, + earlyBirdPrice: group.earlyBirdPrice, + groupPrice: group.groupPrice, + earlyBirdCutoff: moment(group.earlyBirdCutoff).utc().format('YYYY-MM-DD'), + registrationCutoff: moment(group.registrationCutoff).utc().format('YYYY-MM-DD'), + }); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Create Event - Default values have been autofilled from the Event Group -
setFormData(data.formData)} - > - -
-
-
- ); + return ( + + + + Create Event + Default values have been autofilled from the Event Group +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function UpdateEventModal({event, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState({ - ...event, - startDate: moment(event.startDate).utc().format('YYYY-MM-DD'), - endDate: moment(event.endDate).utc().format('YYYY-MM-DD'), - earlyBirdCutoff: moment(event.earlyBirdCutoff).utc().format('YYYY-MM-DD'), - registrationCutoff: moment(event.registrationCutoff).utc().format('YYYY-MM-DD'), - }); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const theme = useTheme(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function UpdateEventModal({ event, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState({ + ...event, + startDate: moment(event.startDate).utc().format('YYYY-MM-DD'), + endDate: moment(event.endDate).utc().format('YYYY-MM-DD'), + earlyBirdCutoff: moment(event.earlyBirdCutoff).utc().format('YYYY-MM-DD'), + registrationCutoff: moment(event.registrationCutoff).utc().format('YYYY-MM-DD'), + }); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const theme = useTheme(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - function formDataToUpdateInput(formData) { - const ret = {}; - Object.keys(schema.properties).map((key) => { - if (formData[key] !== event[key]) ret[key] = {set: formData[key]}; - }); - return ret; - } - return ( - - - -
setFormData(data.formData)} - > - -
-
-
- ); + function formDataToUpdateInput(formData) { + const ret = {}; + Object.keys(schema.properties).map((key) => { + if (formData[key] !== event[key]) ret[key] = { set: formData[key] }; + }); + return ret; + } + return ( + + + +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function DeleteEventModal({event, children, ...props}) { - const [open, setOpen] = useState(false); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function DeleteEventModal({ event, children, ...props }) { + const [open, setOpen] = useState(false); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Remove Event - Are you sure you want to delete this event? -
- There's no turning back! -
- - -
-
- ); + return ( + + + + Remove Event + Are you sure you want to delete this event? +
+ There's no turning back! +
+ + +
+
+ ); } diff --git a/src/components/forms/EventGroup.js b/src/components/forms/EventGroup.js index 2dc3174..e315b78 100644 --- a/src/components/forms/EventGroup.js +++ b/src/components/forms/EventGroup.js @@ -1,219 +1,229 @@ -import React, {useState} from 'react'; -import Form from "@rjsf/chakra-ui"; -import {Box, Button, Heading, Text} from "@codeday/topo/Atom"; -import {Modal} from "react-responsive-modal"; +import React, { useState } from 'react'; +import Form from '@rjsf/chakra-ui'; +import { + Box, Button, Heading, Text, +} from '@codeday/topo/Atom'; +import { Modal } from 'react-responsive-modal'; import 'react-responsive-modal/styles.css'; -import * as Icon from "@codeday/topocons/Icon"; -import {useFetcher} from "../../fetch"; -import {CreateEventGroupMutation, DeleteEventGroupMutation, UpdateEventGroupMutation} from "./EventGroup.gql"; -import {useToasts} from "@codeday/topo/utils"; -import {useRouter} from "next/router"; -import moment from "moment-timezone"; -import {useSession} from "next-auth/react"; -import {useColorModeValue} from "@codeday/topo/Theme"; +import { + UiAdd, UiEdit, UiTrash, UiX, +} from '@codeday/topocons'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import moment from 'moment-timezone'; +import { useSession } from 'next-auth/react'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { CreateEventGroupMutation, DeleteEventGroupMutation, UpdateEventGroupMutation } from './EventGroup.gql'; +import { useFetcher } from '../../fetch'; const schema = { - type: "object", - properties: { - name: { - type: "string", - name: "Name" - }, - startDate: { - type: 'string', - format: 'date', - title: 'Start', - }, - endDate: { - type: 'string', - format: 'date', - title: 'End', - }, - ticketPrice: { - type: "number", - multipleOf: 0.01, - title: "Ticket Price" - }, - earlyBirdPrice: { - type: "number", - multipleOf: 0.01, - title: "Early Bird Price" - }, - groupPrice: { - type: "number", - multipleOf: 0.01, - title: "School Group Price" - }, - earlyBirdCutoff: { - type: 'string', - format: 'date', - title: 'Early Bird Cutoff' - }, - registrationCutoff: { - type: 'string', - format: 'date', - title: 'Registration Cutoff' - }, - contentfulId: { - type: 'string', - title: 'Contentful ID' - } + type: 'object', + properties: { + name: { + type: 'string', + name: 'Name', }, - required: ['name', 'startDate', 'endDate', 'ticketPrice', 'earlyBirdPrice', 'earlyBirdCutoff', 'registrationCutoff', 'contentfulId'] -} + startDate: { + type: 'string', + format: 'date', + title: 'Start', + }, + endDate: { + type: 'string', + format: 'date', + title: 'End', + }, + ticketPrice: { + type: 'number', + multipleOf: 0.01, + title: 'Ticket Price', + }, + earlyBirdPrice: { + type: 'number', + multipleOf: 0.01, + title: 'Early Bird Price', + }, + groupPrice: { + type: 'number', + multipleOf: 0.01, + title: 'School Group Price', + }, + earlyBirdCutoff: { + type: 'string', + format: 'date', + title: 'Early Bird Cutoff', + }, + registrationCutoff: { + type: 'string', + format: 'date', + title: 'Registration Cutoff', + }, + contentfulId: { + type: 'string', + title: 'Contentful ID', + }, + }, + required: ['name', 'startDate', 'endDate', 'ticketPrice', 'earlyBirdPrice', 'earlyBirdCutoff', 'registrationCutoff', 'contentfulId'], +}; const uiSchema = { - /* optional ui schema */ -} + /* optional ui schema */ +}; -export function CreateEventGroupModal({children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState({ - ticketPrice: 20.00, - earlyBirdPrice: 15.00, - }); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function CreateEventGroupModal({ children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState({ + ticketPrice: 20.00, + earlyBirdPrice: 15.00, + }); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Create Event Group -
setFormData(data.formData)} - > - + + Create Event Group + setFormData(data.formData)} + > + - -
-
- ) + }); + await router.replace(router.asPath); + success('Event Group Created'); + onCloseModal(); + } catch (ex) { + error(ex.toString()); + } + setLoading(false); + }} + >Submit + + + + + ); } -export function UpdateEventGroupModal({eventgroup, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState({ - ...eventgroup, - startDate: moment(eventgroup.startDate).utc().format('YYYY-MM-DD'), - endDate: moment(eventgroup.endDate).utc().format('YYYY-MM-DD'), - earlyBirdCutoff: moment(eventgroup.earlyBirdCutoff).utc().format('YYYY-MM-DD'), - registrationCutoff: moment(eventgroup.registrationCutoff).utc().format('YYYY-MM-DD') - }); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function UpdateEventGroupModal({ eventgroup, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState({ + ...eventgroup, + startDate: moment(eventgroup.startDate).utc().format('YYYY-MM-DD'), + endDate: moment(eventgroup.endDate).utc().format('YYYY-MM-DD'), + earlyBirdCutoff: moment(eventgroup.earlyBirdCutoff).utc().format('YYYY-MM-DD'), + registrationCutoff: moment(eventgroup.registrationCutoff).utc().format('YYYY-MM-DD'), + }); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - function formDataToUpdateInput(formData) { - const ret = {} - Object.keys(schema.properties).map((key) => { - if (formData[key] !== eventgroup[key]) ret[key] = {set: formData[key]} - }) - return ret - } + function formDataToUpdateInput(formData) { + const ret = {}; + Object.keys(schema.properties).map((key) => { + if (formData[key] !== eventgroup[key]) ret[key] = { set: formData[key] }; + }); + return ret; + } - return ( - - - -
setFormData(data.formData)} - > - -
-
-
- ) + return ( + + + +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function DeleteEventGroupModal({eventgroup, children, ...props}) { - const [open, setOpen] = useState(false); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function DeleteEventGroupModal({ eventgroup, children, ...props }) { + const [open, setOpen] = useState(false); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Remove Event Group - Are you sure you want to delete this Event Group? -
- There's no turning back!
- - -
-
- ) + return ( + + + + Remove Event Group + Are you sure you want to delete this Event Group? +
+ There's no turning back! +
+ + +
+
+ ); } diff --git a/src/components/forms/EventRestriction.js b/src/components/forms/EventRestriction.js index 7ced06c..9b3d1a0 100644 --- a/src/components/forms/EventRestriction.js +++ b/src/components/forms/EventRestriction.js @@ -1,181 +1,191 @@ -import React, {useState} from 'react'; -import Form from "@rjsf/chakra-ui"; -import {Box, Button, Heading, Text} from "@codeday/topo/Atom"; -import {Modal} from "react-responsive-modal"; +import React, { useState } from 'react'; +import Form from '@rjsf/chakra-ui'; +import { + Box, Button, Heading, Text, +} from '@codeday/topo/Atom'; +import { Modal } from 'react-responsive-modal'; import 'react-responsive-modal/styles.css'; -import * as Icon from "@codeday/topocons/Icon"; -import {useFetcher} from "../../fetch"; -import {useSession} from 'next-auth/react'; import { - CreateEventRestrictionMutation, - DeleteEventRestrictionMutation, - UpdateEventRestrictionMutation -} from "./EventRestriction.gql"; -import {useToasts} from "@codeday/topo/utils"; -import {useRouter} from "next/router"; -import {useColorModeValue} from "@codeday/topo/Theme"; + UiAdd, UiEdit, UiTrash, UiX, +} from '@codeday/topocons'; +import { useSession } from 'next-auth/react'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { + CreateEventRestrictionMutation, + DeleteEventRestrictionMutation, + UpdateEventRestrictionMutation, +} from './EventRestriction.gql'; +import { useFetcher } from '../../fetch'; const schema = { - type: "object", - properties: { - name: { - title: 'Name (internal)', - type: 'string' - }, - title: { - title: 'Title (supports markdown)', - type: 'string' - }, - details: { - title: 'Details (supports markdown)', - type: 'string' - } - } -} + type: 'object', + properties: { + name: { + title: 'Name (internal)', + type: 'string', + }, + title: { + title: 'Title (supports markdown)', + type: 'string', + }, + details: { + title: 'Details (supports markdown)', + type: 'string', + }, + }, +}; const uiSchema = { - details: { - 'ui:widget': 'textarea' - } -} + details: { + 'ui:widget': 'textarea', + }, +}; -export function CreateEventRestrictionModal({children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(/* if you need to set default values, do so here */); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function CreateEventRestrictionModal({ children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(/* if you need to set default values, do so here */); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Create Event Restriction -
setFormData(data.formData)} - > - + + Create Event Restriction + setFormData(data.formData)} + > + - -
-
- ) + }); + await router.replace(router.asPath); + success('EventRestriction Created'); + onCloseModal(); + } catch (ex) { + error(ex.toString()); + } + setLoading(false); + }} + >Submit + + + + + ); } -export function UpdateEventRestrictionModal({eventrestriction, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(eventrestriction); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function UpdateEventRestrictionModal({ eventrestriction, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(eventrestriction); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - function formDataToUpdateInput(formData) { - const ret = {} - Object.keys(schema.properties).map((key) => { - if (formData[key] !== eventrestriction[key]) ret[key] = {set: formData[key]} - }) - return ret - } + function formDataToUpdateInput(formData) { + const ret = {}; + Object.keys(schema.properties).map((key) => { + if (formData[key] !== eventrestriction[key]) ret[key] = { set: formData[key] }; + }); + return ret; + } - return ( - - - -
setFormData(data.formData)} - > - -
-
-
- ) + return ( + + + +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function DeleteEventRestrictionModal({eventrestriction, children, ...props}) { - const [open, setOpen] = useState(false); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function DeleteEventRestrictionModal({ eventrestriction, children, ...props }) { + const [open, setOpen] = useState(false); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Remove EventRestriction - Are you sure you want to delete this Event Restriction? -
- There's no turning back!
- - -
-
- ) + return ( + + + + Remove EventRestriction + Are you sure you want to delete this Event Restriction? +
+ There's no turning back! +
+ + +
+
+ ); } diff --git a/src/components/forms/Guardian.js b/src/components/forms/Guardian.js index 41adc12..3d2b830 100644 --- a/src/components/forms/Guardian.js +++ b/src/components/forms/Guardian.js @@ -1,195 +1,199 @@ -import React, {useState} from 'react'; +import React, { useState } from 'react'; import Form from '@rjsf/chakra-ui'; -import {Box, Button, Heading, Text} from "@codeday/topo/Atom"; -import {Modal} from 'react-responsive-modal'; +import { + Box, Button, Heading, Text, +} from '@codeday/topo/Atom'; +import { Modal } from 'react-responsive-modal'; import 'react-responsive-modal/styles.css'; -import * as Icon from '@codeday/topocons/Icon'; -import {useToasts} from '@codeday/topo/utils'; -import {useRouter} from 'next/router'; -import {useSession} from 'next-auth/react'; -import {CreateGuardianMutation, DeleteGuardianMutation, UpdateGuardianMutation} from './Guardian.gql'; -import {useFetcher} from '../../fetch'; -import {useColorModeValue} from "@codeday/topo/Theme"; +import { + UiAdd, UiEdit, UiTrash, UiX, +} from '@codeday/topocons'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useSession } from 'next-auth/react'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { CreateGuardianMutation, DeleteGuardianMutation, UpdateGuardianMutation } from './Guardian.gql'; +import { useFetcher } from '../../fetch'; export const schema = { - type: 'object', - properties: { - firstName: { - type: 'string', - title: 'First Name', - }, - lastName: { - type: 'string', - title: 'Last Name', - }, - email: { - type: 'string', - title: 'Email', - }, - phone: { - type: 'string', - title: 'Phone', - }, - whatsApp: { - type: 'string', - title: 'WhatsApp', - }, - username: { - type: 'string', - title: 'Username', - }, + type: 'object', + properties: { + firstName: { + type: 'string', + title: 'First Name', }, + lastName: { + type: 'string', + title: 'Last Name', + }, + email: { + type: 'string', + title: 'Email', + }, + phone: { + type: 'string', + title: 'Phone', + }, + whatsApp: { + type: 'string', + title: 'WhatsApp', + }, + username: { + type: 'string', + title: 'Username', + }, + }, }; const uiSchema = { - /* optional ui schema */ + /* optional ui schema */ }; -export function CreateGuardianModal({ticket, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(/* if you need to set default values, do so here */); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function CreateGuardianModal({ ticket, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(/* if you need to set default values, do so here */); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Create Guardian -
setFormData(data.formData)} - > - + + Create Guardian + setFormData(data.formData)} + > + - -
-
- ); + }, + ticketId: ticket.id, + }); + await router.replace(router.asPath); + success('Guardian Created'); + onCloseModal(); + } catch (ex) { + error(ex.toString()); + } + setLoading(false); + }} + >Submit + + + + + ); } -export function UpdateGuardianModal({guardian, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(guardian); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function UpdateGuardianModal({ guardian, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(guardian); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - function formDataToUpdateInput(formData) { - const ret = {}; - Object.keys(schema.properties).map((key) => { - if (formData[key] !== guardian[key]) ret[key] = {set: formData[key]}; - }); - return ret; - } + function formDataToUpdateInput(formData) { + const ret = {}; + Object.keys(schema.properties).map((key) => { + if (formData[key] !== guardian[key]) ret[key] = { set: formData[key] }; + }); + return ret; + } - return ( - - - -
setFormData(data.formData)} - > - -
-
-
- ); + return ( + + + +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function DeleteGuardianModal({guardian, children, ...props}) { - const [open, setOpen] = useState(false); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function DeleteGuardianModal({ guardian, children, ...props }) { + const [open, setOpen] = useState(false); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Remove Guardian - Are you sure you want to delete this Guardian? -
- There's no turning back! -
- - -
-
- ); + return ( + + + + Remove Guardian + Are you sure you want to delete this Guardian? +
+ There's no turning back! +
+ + +
+
+ ); } diff --git a/src/components/forms/Notes.js b/src/components/forms/Notes.js index 1463dfc..76b4292 100644 --- a/src/components/forms/Notes.js +++ b/src/components/forms/Notes.js @@ -1,59 +1,75 @@ -import React, {useState} from "react"; -import InfoBox from "../InfoBox"; -import {Box, Button, Text, Textarea as TextareaInput} from "@codeday/topo/Atom"; -import * as Icon from "@codeday/topocons/Icon" -import {useToasts} from "@codeday/topo/utils"; -import {useFetcher} from "../../fetch"; -import {useRouter} from "next/router"; -import {useSession} from "next-auth/react"; +import React, { useState } from 'react'; +import { + Box, Button, Text, Textarea as TextareaInput, +} from '@codeday/topo/Atom'; +import { UiEdit, UiOk, UiX } from '@codeday/topocons'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useSession } from 'next-auth/react'; +import { useFetcher } from '../../fetch'; +import InfoBox from '../InfoBox'; -export default function Notes({notes, updateMutation, updateId, children, ...props}) { - const [editing, setEditing] = useState(false) - const [loading, setLoading] = useState(false) - const [tempNotes, setTempNotes] = useState(notes) // Temporary notes while the user is editing - const {success, error} = useToasts(); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const router = useRouter() +export default function Notes({ + notes, updateMutation, updateId, children, ...props +}) { + const [editing, setEditing] = useState(false); + const [loading, setLoading] = useState(false); + const [tempNotes, setTempNotes] = useState(notes); // Temporary notes while the user is editing + const { success, error } = useToasts(); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const router = useRouter(); - const okButton = - const trashButton = - const editButton = - const buttons = editing ? {okButton} {trashButton} : editButton; - return ( - - {editing ? - setTempNotes(e.target.value)} - /> : - notes?.split("\n").map((val) => {val})} - {children} - - ) + const okButton = ( + + ); + const trashButton = ( + + ); + const editButton = ( + + ); + const buttons = editing ? {okButton} {trashButton} : editButton; + return ( + + {editing + ? ( + setTempNotes(e.target.value)} + /> + ) + : notes?.split('\n').map((val) => {val})} + {children} + + ); } diff --git a/src/components/forms/Person.js b/src/components/forms/Person.js index 7017cca..b7ed5ae 100644 --- a/src/components/forms/Person.js +++ b/src/components/forms/Person.js @@ -1,189 +1,193 @@ -import React, {useState} from 'react'; +import React, { useState } from 'react'; import Form from '@rjsf/chakra-ui'; -import {Box, Button, Heading, Text} from "@codeday/topo/Atom"; -import {Modal} from 'react-responsive-modal'; +import { + Box, Button, Heading, Text, +} from '@codeday/topo/Atom'; +import { Modal } from 'react-responsive-modal'; import 'react-responsive-modal/styles.css'; -import * as Icon from '@codeday/topocons/Icon'; -import {useToasts} from '@codeday/topo/utils'; -import {useRouter} from 'next/router'; -import {useSession} from 'next-auth/react'; -import {CreatePersonMutation, DeletePersonMutation, UpdatePersonMutation} from './Person.gql'; -import {useFetcher} from '../../fetch'; -import {useColorModeValue} from "@codeday/topo/Theme"; +import { + UiAdd, UiEdit, UiTrash, UiX, +} from '@codeday/topocons'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useSession } from 'next-auth/react'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { CreatePersonMutation, DeletePersonMutation, UpdatePersonMutation } from './Person.gql'; +import { useFetcher } from '../../fetch'; export const schema = { - type: 'object', - properties: { - firstName: { - type: 'string', - title: 'First Name', - }, - lastName: { - type: 'string', - title: 'Last Name', - }, - email: { - type: 'string', - title: 'Email', - }, - phone: { - type: 'string', - title: 'Phone', - }, - pronouns: { - type: 'string', - title: 'Pronouns', - }, + type: 'object', + properties: { + firstName: { + type: 'string', + title: 'First Name', }, + lastName: { + type: 'string', + title: 'Last Name', + }, + email: { + type: 'string', + title: 'Email', + }, + phone: { + type: 'string', + title: 'Phone', + }, + pronouns: { + type: 'string', + title: 'Pronouns', + }, + }, }; const uiSchema = { - /* optional ui schema */ + /* optional ui schema */ }; -export function CreatePersonModal({children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(/* if you need to set default values, do so here */); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function CreatePersonModal({ children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(/* if you need to set default values, do so here */); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Create Person -
setFormData(data.formData)} - > - + + Create Person + setFormData(data.formData)} + > + - -
-
- ); + }); + await router.replace(router.asPath); + success('Person Created'); + onCloseModal(); + } catch (ex) { + error(ex.toString()); + } + setLoading(false); + }} + >Submit + + + + + ); } -export function UpdatePersonModal({person, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(person); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function UpdatePersonModal({ person, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(person); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - function formDataToUpdateInput(formData) { - const ret = {}; - Object.keys(schema.properties).map((key) => { - if (formData[key] !== person[key]) ret[key] = {set: formData[key]}; - }); - return ret; - } + function formDataToUpdateInput(formData) { + const ret = {}; + Object.keys(schema.properties).map((key) => { + if (formData[key] !== person[key]) ret[key] = { set: formData[key] }; + }); + return ret; + } - return ( - - - -
setFormData(data.formData)} - > - -
-
-
- ); + return ( + + + +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function DeletePersonModal({person, children, ...props}) { - const [open, setOpen] = useState(false); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function DeletePersonModal({ person, children, ...props }) { + const [open, setOpen] = useState(false); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Remove Person - Are you sure you want to delete this Person? -
- There's no turning back! -
- - -
-
- ); + return ( + + + + Remove Person + Are you sure you want to delete this Person? +
+ There's no turning back! +
+ + +
+
+ ); } diff --git a/src/components/forms/PromoCode.js b/src/components/forms/PromoCode.js index 29fe59d..86a1873 100644 --- a/src/components/forms/PromoCode.js +++ b/src/components/forms/PromoCode.js @@ -1,277 +1,288 @@ -import React, {useState} from 'react'; -import Form from "@rjsf/chakra-ui"; -import {Box, Button, Heading, Text} from "@codeday/topo/Atom"; -import {Modal} from "react-responsive-modal"; +import React, { useState } from 'react'; +import Form from '@rjsf/chakra-ui'; +import { + Box, Button, Heading, Text, +} from '@codeday/topo/Atom'; +import { Modal } from 'react-responsive-modal'; import 'react-responsive-modal/styles.css'; -import * as Icon from "@codeday/topocons/Icon"; -import {useFetcher} from "../../fetch"; -import {CreatePromoCodeMutation, DeletePromoCodeMutation, UpdatePromoCodeMutation, SetPromoCodeMetatataMutation} from "./PromoCode.gql"; -import {useToasts} from "@codeday/topo/utils"; -import {useRouter} from "next/router"; -import {useSession} from "next-auth/react"; -import {useColorModeValue} from "@codeday/topo/Theme"; +import { + UiAdd, UiEdit, UiTrash, UiX, +} from '@codeday/topocons'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useSession } from 'next-auth/react'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { + CreatePromoCodeMutation, DeletePromoCodeMutation, UpdatePromoCodeMutation, SetPromoCodeMetatataMutation, +} from './PromoCode.gql'; +import { useFetcher } from '../../fetch'; -const characters = "ABCDEFGHKPQRSTUVWXYZ"; +const characters = 'ABCDEFGHKPQRSTUVWXYZ'; function generatePromoCode(length) { - let result = ''; - for ( let i = 0; i < length; i++ ) { - result += characters.charAt(Math.floor(Math.random() * characters.length)); - } - return result; + let result = ''; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * characters.length)); + } + return result; } const schema = { - type: "object", - properties: { - code: { - type: 'string', - title: 'Code' - }, - type: { - type: 'string', - title: 'Type', - enum: ["SUBTRACT", "PERCENT"], - enumNames: ["Subtract Fixed Value", "Percent Discount"] - }, - amount: { - type: 'number', - multipleOf: 0.01 - }, - uses: { - type: 'number', - multipleOf: 1, - title: 'Uses' - }, - enablesUber: { - type: 'boolean', - title: 'Enables requesting a free Uber ride?', - description: '(For promo codes provided exclusively to low-income schools.)', - }, - enablesLaptops: { - type: 'boolean', - title: 'Enables requesting a free laptop?', - description: '(For promo codes provided exclusively to low-income schools.)', - }, - } -} - -const uiSchema = { + type: 'object', + properties: { + code: { + type: 'string', + title: 'Code', + }, + type: { + type: 'string', + title: 'Type', + enum: ['SUBTRACT', 'PERCENT'], + enumNames: ['Subtract Fixed Value', 'Percent Discount'], + }, + amount: { + type: 'number', + multipleOf: 0.01, + }, uses: { - "ui:help": "Leave this blank for the code to have unlimited uses" + type: 'number', + multipleOf: 1, + title: 'Uses', }, enablesUber: { - "ui:help": '(For promo codes provided exclusively to low-income schools.)', + type: 'boolean', + title: 'Enables requesting a free Uber ride?', + description: '(For promo codes provided exclusively to low-income schools.)', }, enablesLaptops: { - "ui:help": '(This is for a laptop to keep, NOT a loaner laptop. For promo codes provided exclusively to low-income schools.)', + type: 'boolean', + title: 'Enables requesting a free laptop?', + description: '(For promo codes provided exclusively to low-income schools.)', }, -} + }, +}; -export function CreatePromoCodeModal({event, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(/* if you need to set default values, do so here */); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +const uiSchema = { + uses: { + 'ui:help': 'Leave this blank for the code to have unlimited uses', + }, + enablesUber: { + 'ui:help': '(For promo codes provided exclusively to low-income schools.)', + }, + enablesLaptops: { + 'ui:help': '(This is for a laptop to keep, NOT a loaner laptop. For promo codes provided exclusively to low-income schools.)', + }, +}; + +export function CreatePromoCodeModal({ event, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(/* if you need to set default values, do so here */); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Create Promo Code -
setFormData(data.formData)} - > - -
-
-
- ) + return ( + + + + Create Promo Code +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function UpdatePromoCodeModal({promocode, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(promocode); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function UpdatePromoCodeModal({ promocode, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(promocode); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - function formDataToUpdateInput(formData) { - const ret = {} - Object.keys(schema.properties).map((key) => { - if (formData[key] !== promocode[key]) ret[key] = {set: formData[key]} - }) - return ret - } + function formDataToUpdateInput(formData) { + const ret = {}; + Object.keys(schema.properties).map((key) => { + if (formData[key] !== promocode[key]) ret[key] = { set: formData[key] }; + }); + return ret; + } - return ( - - - -
setFormData(data.formData)} - > - -
-
-
- ) + return ( + + + +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function DeletePromoCodeModal({promocode, children, ...props}) { - const [open, setOpen] = useState(false); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function DeletePromoCodeModal({ promocode, children, ...props }) { + const [open, setOpen] = useState(false); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Remove PromoCode - Are you sure you want to delete this Promo Code? -
- There's no turning back!
- - -
-
- ) + return ( + + + + Remove PromoCode + Are you sure you want to delete this Promo Code? +
+ There's no turning back! +
+ + +
+
+ ); } -export function CreateScholarshipCodeButton({event, children, ...props}) { - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false) - const {success, error} = useToasts(); - const router = useRouter(); +export function CreateScholarshipCodeButton({ event, children, ...props }) { + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const router = useRouter(); - return ( - - ) + setLoading(false); + }} + > + Generate Scholarship Code + + ); } diff --git a/src/components/forms/ScheduleItem.js b/src/components/forms/ScheduleItem.js index 4d7614c..dd81fd0 100644 --- a/src/components/forms/ScheduleItem.js +++ b/src/components/forms/ScheduleItem.js @@ -1,265 +1,269 @@ -import React, {useState} from 'react'; +import React, { useState } from 'react'; import Form from '@rjsf/chakra-ui'; -import {Box, Button, Heading, Text} from "@codeday/topo/Atom"; -import {Modal} from 'react-responsive-modal'; +import { + Box, Button, Heading, Text, +} from '@codeday/topo/Atom'; +import { Modal } from 'react-responsive-modal'; import 'react-responsive-modal/styles.css'; -import * as Icon from '@codeday/topocons/Icon'; -import {useToasts} from '@codeday/topo/utils'; -import {useRouter} from 'next/router'; -import {useSession} from 'next-auth/react'; -import {CreateScheduleItemMutation, DeleteScheduleItemMutation, UpdateScheduleItemMutation} from './ScheduleItem.gql'; -import {useFetcher} from '../../fetch'; -import {useColorModeValue} from "@codeday/topo/Theme"; +import { + UiAdd, UiEdit, UiTrash, UiX, +} from '@codeday/topocons'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useSession } from 'next-auth/react'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { CreateScheduleItemMutation, DeleteScheduleItemMutation, UpdateScheduleItemMutation } from './ScheduleItem.gql'; +import { useFetcher } from '../../fetch'; const schema = { - type: 'object', - properties: { - name: { - type: 'string', - title: 'Name', - }, - type: { - type: 'string', - title: 'Type', - examples: [ - "Workshop", - "Activity", - "Meal", - "Deadline", - ] - }, - description: { - type: 'string', - title: 'Description', - }, - link: { - type: 'string', - title: 'Link', - }, - start: { - type: 'string', - format: 'date-time', - title: 'Start', - }, - end: { - type: 'string', - format: 'date-time', - title: 'End', - }, - hostName: { - type: 'string', - title: 'Host Name', - }, - hostPronoun: { - type: 'string', - title: 'Host Pronouns', - }, - organizerName: { - type: 'string', - title: 'Organizer Name', - }, - organizerEmail: { - type: 'string', - title: 'Organizer Email', - }, - organizerPhone: { - type: 'string', - title: 'Organizer Phone', - }, - finalized: { - type: 'boolean', - title: 'Published', - }, - internal: { - type: 'boolean', - title: 'Internal', - }, + type: 'object', + properties: { + name: { + type: 'string', + title: 'Name', }, - required: [ - 'start', 'name', - ], -}; - -const uiSchema = { type: { - 'ui:help': 'What kind of Schedule Item is this?', + type: 'string', + title: 'Type', + examples: [ + 'Workshop', + 'Activity', + 'Meal', + 'Deadline', + ], + }, + description: { + type: 'string', + title: 'Description', + }, + link: { + type: 'string', + title: 'Link', + }, + start: { + type: 'string', + format: 'date-time', + title: 'Start', + }, + end: { + type: 'string', + format: 'date-time', + title: 'End', + }, + hostName: { + type: 'string', + title: 'Host Name', + }, + hostPronoun: { + type: 'string', + title: 'Host Pronouns', + }, + organizerName: { + type: 'string', + title: 'Organizer Name', + }, + organizerEmail: { + type: 'string', + title: 'Organizer Email', + }, + organizerPhone: { + type: 'string', + title: 'Organizer Phone', }, finalized: { - 'ui:help': 'Is this schedule item ready to be displayed on the event website?', + type: 'boolean', + title: 'Published', }, internal: { - 'ui:help': 'Internal Schedule Items are only shown to volunteers and staff. An internal event must still be marked as "published" to be displayed internally', + type: 'boolean', + title: 'Internal', }, + }, + required: [ + 'start', 'name', + ], +}; + +const uiSchema = { + type: { + 'ui:help': 'What kind of Schedule Item is this?', + }, + finalized: { + 'ui:help': 'Is this schedule item ready to be displayed on the event website?', + }, + internal: { + 'ui:help': 'Internal Schedule Items are only shown to volunteers and staff. An internal event must still be marked as "published" to be displayed internally', + }, }; export function CreateScheduleItemModal({ - event, group, children, ...props - }) { - if (event && group) throw 'CreateScheduleItemModal must be passed only one of either `event` or `group`'; - if (!event && !group) throw 'CreateScheduleItemModal must be passed `event` or `group`'; - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(/* if you need to set default values, do so here */); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); + event, group, children, ...props +}) { + if (event && group) throw 'CreateScheduleItemModal must be passed only one of either `event` or `group`'; + if (!event && !group) throw 'CreateScheduleItemModal must be passed `event` or `group`'; + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(/* if you need to set default values, do so here */); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Create Schedule Item -
setFormData(data.formData)} - > - + + Create Schedule Item + setFormData(data.formData)} + > + - -
-
- ); + }); + await router.replace(router.asPath); + success('Schedule Item Created'); + onCloseModal(); + } catch (ex) { + error(ex.toString()); + } + setLoading(false); + }} + >Submit + + + + + ); } -export function UpdateScheduleItemModal({scheduleitem, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(scheduleitem); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function UpdateScheduleItemModal({ scheduleitem, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(scheduleitem); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - function formDataToUpdateInput(formData) { - const ret = {}; - Object.keys(schema.properties).map((key) => { - if (formData[key] !== scheduleitem[key]) ret[key] = {set: formData[key]}; - }); - return ret; - } + function formDataToUpdateInput(formData) { + const ret = {}; + Object.keys(schema.properties).map((key) => { + if (formData[key] !== scheduleitem[key]) ret[key] = { set: formData[key] }; + }); + return ret; + } - return ( - - - -
setFormData(data.formData)} - > - -
-
-
- ); + return ( + + + +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function DeleteScheduleItemModal({scheduleitem, children, ...props}) { - const [open, setOpen] = useState(false); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function DeleteScheduleItemModal({ scheduleitem, children, ...props }) { + const [open, setOpen] = useState(false); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Remove ScheduleItem - Are you sure you want to delete this Schedule Item? -
- There's no turning back! -
- - -
-
- ); + return ( + + + + Remove ScheduleItem + Are you sure you want to delete this Schedule Item? +
+ There's no turning back! +
+ + +
+
+ ); } diff --git a/src/components/forms/Sponsor.js b/src/components/forms/Sponsor.js index 721b11a..4f48ee9 100644 --- a/src/components/forms/Sponsor.js +++ b/src/components/forms/Sponsor.js @@ -1,226 +1,230 @@ -import React, {useState} from 'react'; +import React, { useState } from 'react'; import Form from '@rjsf/chakra-ui'; -import {Box, Button, Heading, Text} from "@codeday/topo/Atom"; -import {Modal} from 'react-responsive-modal'; +import { + Box, Button, Heading, Text, +} from '@codeday/topo/Atom'; +import { Modal } from 'react-responsive-modal'; import 'react-responsive-modal/styles.css'; -import * as Icon from '@codeday/topocons/Icon'; -import {useToasts} from '@codeday/topo/utils'; -import {useRouter} from 'next/router'; -import {useSession} from 'next-auth/react'; -import {CreateSponsorMutation, DeleteSponsorMutation, UpdateSponsorMutation} from './Sponsor.gql'; -import {useFetcher} from '../../fetch'; -import {useColorModeValue} from "@codeday/topo/Theme"; +import { + UiAdd, UiEdit, UiTrash, UiX, +} from '@codeday/topocons'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useSession } from 'next-auth/react'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { CreateSponsorMutation, DeleteSponsorMutation, UpdateSponsorMutation } from './Sponsor.gql'; +import { useFetcher } from '../../fetch'; const schema = { - type: 'object', - properties: { - name: { - title: 'Name', - type: 'string', - }, - link: { - title: 'Link', - type: 'string' - }, - description: { - title: 'Description', - type: 'string', - }, - amount: { - title: 'Sponsorship Amount', - type: 'integer', - }, - perks: { - title: 'Perks', - type: 'string', - }, - contactName: { - title: 'Contact Name', - type: 'string', - }, - contactPhone: { - title: 'Contact Phone', - type: 'string', - }, - contactEmail: { - title: 'Contact Email', - type: 'string', - }, + type: 'object', + properties: { + name: { + title: 'Name', + type: 'string', + }, + link: { + title: 'Link', + type: 'string', }, -}; - -const uiSchema = { description: { - 'ui:help': '**WILL BE DISPLAYED TO PUBLIC** \n' - + 'A short blurb describing the company (can be taken from their website/google)', + title: 'Description', + type: 'string', }, amount: { - 'ui:help': 'If sponsorship was not cash (for example food) enter a rough estimate of the goods provided', + title: 'Sponsorship Amount', + type: 'integer', }, perks: { - 'ui:help': 'Is the company providing something to CodeDay attendees?', + title: 'Perks', + type: 'string', + }, + contactName: { + title: 'Contact Name', + type: 'string', + }, + contactPhone: { + title: 'Contact Phone', + type: 'string', }, - /* optional ui schema */ + contactEmail: { + title: 'Contact Email', + type: 'string', + }, + }, }; -export function CreateSponsorModal({event, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +const uiSchema = { + description: { + 'ui:help': '**WILL BE DISPLAYED TO PUBLIC** \n' + + 'A short blurb describing the company (can be taken from their website/google)', + }, + amount: { + 'ui:help': 'If sponsorship was not cash (for example food) enter a rough estimate of the goods provided', + }, + perks: { + 'ui:help': 'Is the company providing something to CodeDay attendees?', + }, + /* optional ui schema */ +}; - return ( - - - - Create Sponsor -
setFormData(data.formData)} - > - -
-
-
- ); +export function CreateSponsorModal({ event, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); + + return ( + + + + Create Sponsor +
setFormData(data.formData)} + > + +
+
+
+ ); } export function UpdateSponsorModal( - { - sponsor, children, ...props - }, + { + sponsor, children, ...props + }, ) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(sponsor); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(sponsor); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - function formDataToUpdateInput(formData) { - const ret = {}; - Object.keys(schema.properties).map((key) => { - if (formData[key] !== sponsor[key]) ret[key] = {set: formData[key]}; - }); - return ret; - } + function formDataToUpdateInput(formData) { + const ret = {}; + Object.keys(schema.properties).map((key) => { + if (formData[key] !== sponsor[key]) ret[key] = { set: formData[key] }; + }); + return ret; + } - return ( - - - -
setFormData(data.formData)} - > - -
-
-
- ); + return ( + + + +
setFormData(data.formData)} + > + +
+
+
+ ); } export function DeleteSponsorModal( - { - sponsor, children, ...props - }, + { + sponsor, children, ...props + }, ) { - const [open, setOpen] = useState(false); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); + const [open, setOpen] = useState(false); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Remove Sponsor - Are you sure you want to delete this Sponsor? -
- There's no turning back! -
- - -
-
- ); + return ( + + + + Remove Sponsor + Are you sure you want to delete this Sponsor? +
+ There's no turning back! +
+ + +
+
+ ); } diff --git a/src/components/forms/Ticket.js b/src/components/forms/Ticket.js index f14584e..1cfa866 100644 --- a/src/components/forms/Ticket.js +++ b/src/components/forms/Ticket.js @@ -1,246 +1,248 @@ -import React, {useState} from 'react'; +import React, { useState } from 'react'; import Form from '@rjsf/chakra-ui'; -import {Box, Button, Heading, Text} from "@codeday/topo/Atom"; -import {Modal} from 'react-responsive-modal'; +import { + Box, Button, Heading, Text, +} from '@codeday/topo/Atom'; +import { Modal } from 'react-responsive-modal'; import 'react-responsive-modal/styles.css'; -import * as Icons from '@codeday/topocons/Icon'; +import * as Icons from '@codeday/topocons'; import { Icon } from '@chakra-ui/react'; -import {useToasts} from '@codeday/topo/utils'; -import {useRouter} from 'next/router'; -import {useSession} from 'next-auth/react'; -import {CreateTicketMutation, DeleteTicketMutation, UpdateTicketMutation} from './Ticket.gql'; -import {useFetcher} from '../../fetch'; -import {useColorModeValue} from "@codeday/topo/Theme"; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useSession } from 'next-auth/react'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { CreateTicketMutation, DeleteTicketMutation, UpdateTicketMutation } from './Ticket.gql'; +import { useFetcher } from '../../fetch'; export const ticketTypeEnum = [ - { - type: 'string', - title: 'Student', - enum: ['STUDENT'] + { + type: 'string', + title: 'Student', + enum: ['STUDENT'], + }, + { + type: 'string', + title: 'Teacher', + enum: ['TEACHER'], + }, + { + type: 'string', + title: 'VIP', + enum: ['VIP'], + }, + { + type: 'string', + title: 'Mentor', + enum: ['MENTOR'], + }, + { + type: 'string', + title: 'Judge', + enum: ['JUDGE'], + }, + { + type: 'string', + title: 'Staff', + enum: ['STAFF'], + }, +]; + +const schema = { + type: 'object', + properties: { + firstName: { + type: 'string', + title: 'First Name', }, - { - type: 'string', - title: 'Teacher', - enum: ['TEACHER'] + lastName: { + type: 'string', + title: 'Last Name', }, - { - type: 'string', - title: 'VIP', - enum: ['VIP'] + email: { + type: 'string', + title: 'Email', }, - { - type: 'string', - title: 'Mentor', - enum: ['MENTOR'] + phone: { + type: 'string', + title: 'Phone', }, - { - type: 'string', - title: 'Judge', - enum: ['JUDGE'] + whatsApp: { + type: 'string', + title: 'WhatsApp', }, - { - type: 'string', - title: 'Staff', - enum: ['STAFF'] - } -] - -const schema = { - type: 'object', - properties: { - firstName: { - type: 'string', - title: 'First Name', - }, - lastName: { - type: 'string', - title: 'Last Name', - }, - email: { - type: 'string', - title: 'Email', - }, - phone: { - type: 'string', - title: 'Phone', - }, - whatsApp: { - type: 'string', - title: 'WhatsApp', - }, - age: { - type: 'integer', - title: 'Age', - }, - type: { - type: 'string', - title: 'Type', - default: 'STUDENT', - anyOf: ticketTypeEnum - }, - username: { - type: 'string', - title: 'Username', - }, + age: { + type: 'integer', + title: 'Age', }, - required: ['firstName', 'lastName'] + type: { + type: 'string', + title: 'Type', + default: 'STUDENT', + anyOf: ticketTypeEnum, + }, + username: { + type: 'string', + title: 'Username', + }, + }, + required: ['firstName', 'lastName'], }; const uiSchema = { - username: { - 'ui:help': 'Username from account.codeday.org. RECOMMENDED FOR STAFF as this affects how you are displayed to the public on event pages.' - } + username: { + 'ui:help': 'Username from account.codeday.org. RECOMMENDED FOR STAFF as this affects how you are displayed to the public on event pages.', + }, }; -export function CreateTicketModal({event, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(/* if you need to set default values, do so here */); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function CreateTicketModal({ event, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(/* if you need to set default values, do so here */); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Create Ticket -
setFormData(data.formData)} - > - + + Create Ticket + setFormData(data.formData)} + > + - -
-
- ); + onCloseModal(); + } catch (ex) { + error(ex.toString()); + } + setLoading(false); + }} + >Submit + + + + + ); } -export function UpdateTicketModal({ticket, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(ticket); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function UpdateTicketModal({ ticket, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(ticket); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - function formDataToUpdateInput(formData) { - const ret = {}; - Object.keys(schema.properties).map((key) => { - if (formData[key] !== ticket[key]) ret[key] = {set: formData[key]}; - }); - return ret; - } + function formDataToUpdateInput(formData) { + const ret = {}; + Object.keys(schema.properties).map((key) => { + if (formData[key] !== ticket[key]) ret[key] = { set: formData[key] }; + }); + return ret; + } - return ( - - - -
setFormData(data.formData)} - > - -
-
-
- ); + return ( + + + +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function DeleteTicketModal({ticket, children, ...props}) { - const [open, setOpen] = useState(false); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function DeleteTicketModal({ ticket, children, ...props }) { + const [open, setOpen] = useState(false); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Remove Ticket - Are you sure you want to delete this Ticket? -
- There's no turning back! -
- - -
-
- ); + return ( + + + + Remove Ticket + Are you sure you want to delete this Ticket? +
+ There's no turning back! +
+ + +
+
+ ); } diff --git a/src/components/forms/Venue.js b/src/components/forms/Venue.js index 72389ac..38341eb 100644 --- a/src/components/forms/Venue.js +++ b/src/components/forms/Venue.js @@ -1,228 +1,232 @@ -import React, {useState} from 'react'; +import React, { useState } from 'react'; import Form from '@rjsf/chakra-ui'; -import {Box, Button, Heading, Text} from "@codeday/topo/Atom"; -import {Modal} from 'react-responsive-modal'; +import { + Box, Button, Heading, Text, +} from '@codeday/topo/Atom'; +import { Modal } from 'react-responsive-modal'; import 'react-responsive-modal/styles.css'; -import * as Icon from '@codeday/topocons/Icon'; -import {useToasts} from '@codeday/topo/utils'; -import {useRouter} from 'next/router'; -import {useSession} from 'next-auth/react'; -import {CreateVenueMutation, DeleteVenueMutation, UpdateVenueMutation} from './Venue.gql'; -import {useFetcher} from '../../fetch'; -import {InfoAlert} from '../Alert'; -import {useColorModeValue} from "@codeday/topo/Theme"; +import { + UiAdd, UiEdit, UiTrash, UiX, +} from '@codeday/topocons'; +import { useToasts } from '@codeday/topo/utils'; +import { useRouter } from 'next/router'; +import { useSession } from 'next-auth/react'; +import { useColorModeValue } from '@codeday/topo/Theme'; +import { CreateVenueMutation, DeleteVenueMutation, UpdateVenueMutation } from './Venue.gql'; +import { useFetcher } from '../../fetch'; +import { InfoAlert } from '../Alert'; const schema = { - type: 'object', - properties: { - name: { - type: 'string', - title: 'Name', - }, - capacity: { - type: 'integer', - title: 'Capacity', - }, - addressLine1: { - type: 'string', - title: 'Address Line 1' - }, - addressLine2: { - type: 'string', - title: 'Address Line 2', - }, - addressLine3: { - type: 'string', - title: 'Address Line 3', - }, - city: { - type: 'string', - title: 'City', - }, - state: { - type: 'string', - title: 'State' - }, - stateAbbreviation: { - type: 'string', - title: 'State Abbreviation' - }, - zipCode: { - type: 'string', - title: 'ZIP code' - }, - country: { - type: 'string', - title: 'Country' - }, - countryAbbreviation: { - type: 'string', - title: 'Country Abbreviation' - }, - mapLink: { - type: 'string', - title: 'Map link', - }, - contactName: { - type: 'string', - title: 'Contact Name', - }, - contactEmail: { - type: 'string', - title: 'Contact Email', - }, - contactPhone: { - type: 'string', - title: 'Contact Phone', - }, + type: 'object', + properties: { + name: { + type: 'string', + title: 'Name', }, + capacity: { + type: 'integer', + title: 'Capacity', + }, + addressLine1: { + type: 'string', + title: 'Address Line 1', + }, + addressLine2: { + type: 'string', + title: 'Address Line 2', + }, + addressLine3: { + type: 'string', + title: 'Address Line 3', + }, + city: { + type: 'string', + title: 'City', + }, + state: { + type: 'string', + title: 'State', + }, + stateAbbreviation: { + type: 'string', + title: 'State Abbreviation', + }, + zipCode: { + type: 'string', + title: 'ZIP code', + }, + country: { + type: 'string', + title: 'Country', + }, + countryAbbreviation: { + type: 'string', + title: 'Country Abbreviation', + }, + mapLink: { + type: 'string', + title: 'Map link', + }, + contactName: { + type: 'string', + title: 'Contact Name', + }, + contactEmail: { + type: 'string', + title: 'Contact Email', + }, + contactPhone: { + type: 'string', + title: 'Contact Phone', + }, + }, }; -export function CreateVenueModal({event, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function CreateVenueModal({ event, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Create Venue - You can leave anything you aren't sure of yet blank and edit later! -
setFormData(data.formData)} - > - -
-
-
- ); + return ( + + + + Create Venue + You can leave anything you aren't sure of yet blank and edit later! +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function UpdateVenueModal({venue, children, ...props}) { - const [open, setOpen] = useState(false); - const [formData, setFormData] = useState(venue); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function UpdateVenueModal({ venue, children, ...props }) { + const [open, setOpen] = useState(false); + const [formData, setFormData] = useState(venue); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - function formDataToUpdateInput(formData) { - const ret = {}; - Object.keys(schema.properties).map((key) => { - if (formData[key] !== venue[key]) ret[key] = {set: formData[key]}; - }); - return ret; - } + function formDataToUpdateInput(formData) { + const ret = {}; + Object.keys(schema.properties).map((key) => { + if (formData[key] !== venue[key]) ret[key] = { set: formData[key] }; + }); + return ret; + } - return ( - - - -
setFormData(data.formData)} - > - -
-
-
- ); + return ( + + + +
setFormData(data.formData)} + > + +
+
+
+ ); } -export function DeleteVenueModal({venue, children, ...props}) { - const [open, setOpen] = useState(false); - const { data: session } = useSession(); - const fetch = useFetcher(session); - const [loading, setLoading] = useState(false); - const {success, error} = useToasts(); - const onOpenModal = () => setOpen(true); - const onCloseModal = () => setOpen(false); - const router = useRouter(); +export function DeleteVenueModal({ venue, children, ...props }) { + const [open, setOpen] = useState(false); + const { data: session } = useSession(); + const fetch = useFetcher(session); + const [loading, setLoading] = useState(false); + const { success, error } = useToasts(); + const onOpenModal = () => setOpen(true); + const onCloseModal = () => setOpen(false); + const router = useRouter(); - return ( - - - - Remove Venue - Are you sure you want to delete this venue? -
- There's no turning back! -
- - -
-
- ); + return ( + + + + Remove Venue + Are you sure you want to delete this venue? +
+ There's no turning back! +
+ + +
+
+ ); } diff --git a/src/fetch.js b/src/fetch.js index 2f075f3..8aba089 100644 --- a/src/fetch.js +++ b/src/fetch.js @@ -1,20 +1,20 @@ -import {apiFetch, useToasts} from '@codeday/topo/utils' -import {useSession} from 'next-auth/react'; +import { apiFetch, useToasts } from '@codeday/topo/utils'; +import { useSession } from 'next-auth/react'; export function useFetcher(_, variables) { - const { data: session } = useSession(); - const { error } = useToasts(); - if (!session || !session?.clearAuthToken) return () => error(`Session token not provided.`); - return (q, v, h) => apiFetch(q, {...v, ...variables}, { - ...h, - 'X-Clear-Authorization': `Bearer ${session?.clearAuthToken}` - }) + const { data: session } = useSession(); + const { error } = useToasts(); + if (!session || !session?.clearAuthToken) return () => error(`Session token not provided.`); + return (q, v, h) => apiFetch(q, { ...v, ...variables }, { + ...h, + 'X-Clear-Authorization': `Bearer ${session?.clearAuthToken}`, + }); } export function getFetcher(session, variables) { - if (!session || !session?.clearAuthToken) return () => { throw new Error(`Session token not provided.`) }; - return (q, v, h) => apiFetch(q, {...v, ...variables}, { - ...h, - 'X-Clear-Authorization': `Bearer ${session?.clearAuthToken}` - }) + if (!session || !session?.clearAuthToken) return () => { throw new Error(`Session token not provided.`); }; + return (q, v, h) => apiFetch(q, { ...v, ...variables }, { + ...h, + 'X-Clear-Authorization': `Bearer ${session?.clearAuthToken}`, + }); } diff --git a/src/pages/404.js b/src/pages/404.js index 7175d59..b38ff27 100644 --- a/src/pages/404.js +++ b/src/pages/404.js @@ -1,14 +1,16 @@ -import Opossum from "../components/Opossum"; -import {Box, Heading, Link, Text} from "@codeday/topo/Atom"; -import Page from "../components/Page" +import { + Box, Heading, Link, Text, +} from '@codeday/topo/Atom'; +import Opossum from '../components/Opossum'; +import Page from '../components/Page'; export default function NotFound() { return ( - + - + Oh no! Error 404 There seems to be nothing here. Go home diff --git a/src/pages/500.js b/src/pages/500.js index 46d9f1f..4447144 100644 --- a/src/pages/500.js +++ b/src/pages/500.js @@ -1,14 +1,16 @@ -import Opossum from "../components/Opossum"; -import {Box, Heading, Link, Text} from "@codeday/topo/Atom"; -import Page from "../components/Page" +import { + Box, Heading, Link, Text, +} from '@codeday/topo/Atom'; +import Opossum from '../components/Opossum'; +import Page from '../components/Page'; export default function ServerError() { return ( - - + + - + Oh no! Error 500 There seems to have been an error on our part. Go home diff --git a/src/pages/_app.js b/src/pages/_app.js index d802e82..e2ffbe3 100644 --- a/src/pages/_app.js +++ b/src/pages/_app.js @@ -1,33 +1,30 @@ -import {ThemeProvider, getServerSideProps} from '@codeday/topo/Theme'; +import { ThemeProvider, getServerSideProps } from '@codeday/topo/Theme'; import PropTypes from 'prop-types'; import moment from 'moment-timezone'; -import {getSession, SessionProvider} from "next-auth/react" -import {QueryProvider} from '../providers/query'; +import { getSession, SessionProvider } from 'next-auth/react'; +import { QueryProvider } from '../providers/query'; -export default function CustomApp({ Component, pageProps: {query, cookies, ...pageProps}, session }) { - moment.tz.setDefault('Etc/UTC'); +export default function CustomApp({ Component, pageProps: { query, cookies, ...pageProps }, session }) { + moment.tz.setDefault('Etc/UTC'); - return ( - - - - - - - - ); + return ( + + + + + + + + ); } CustomApp.propTypes = { - Component: PropTypes.elementType.isRequired, - pageProps: PropTypes.object, + Component: PropTypes.elementType.isRequired, + pageProps: PropTypes.object, }; CustomApp.defaultProps = { - pageProps: {}, + pageProps: {}, }; -CustomApp.getInitialProps = async ({ ctx }) => { - return { - session: await getSession(ctx), - ...getServerSideProps({ req: ctx.req }).props, - }; -}; - +CustomApp.getInitialProps = async ({ ctx }) => ({ + session: await getSession(ctx), + ...getServerSideProps({ req: ctx.req }).props, +}); diff --git a/src/pages/_document.js b/src/pages/_document.js index adb7d24..2e598fd 100644 --- a/src/pages/_document.js +++ b/src/pages/_document.js @@ -1,5 +1,7 @@ import React from 'react'; -import Document, {Head, Html, Main, NextScript,} from 'next/document'; +import Document, { + Head, Html, Main, NextScript, +} from 'next/document'; import { ColorModeScript } from '@codeday/topo/Theme'; export default class CustomDocument extends Document { diff --git a/src/pages/admin/emailTemplates/index.js b/src/pages/admin/emailTemplates/index.js index 0d7b2df..bc43a73 100644 --- a/src/pages/admin/emailTemplates/index.js +++ b/src/pages/admin/emailTemplates/index.js @@ -1,40 +1,39 @@ import React from 'react'; +import Masonry, { ResponsiveMasonry } from 'react-responsive-masonry'; +import { getSession } from 'next-auth/react'; import { - CreateEmailTemplateModal, - DeleteEmailTemplateModal, - UpdateEmailTemplateModal -} from "../../../components/forms/EmailTemplate"; -import Masonry, {ResponsiveMasonry} from 'react-responsive-masonry'; -import Page from "../../../components/Page"; -import Breadcrumbs from "../../../components/Breadcrumbs"; -import {getSession} from "next-auth/react"; -import {getFetcher} from "../../../fetch"; -import {getEmailTemplatesQuery} from "./index.gql" -import EmailTemplate from "../../../components/EmailTemplate"; + CreateEmailTemplateModal, + DeleteEmailTemplateModal, + UpdateEmailTemplateModal, +} from '../../../components/forms/EmailTemplate'; +import Page from '../../../components/Page'; +import Breadcrumbs from '../../../components/Breadcrumbs'; +import { getFetcher } from '../../../fetch'; +import { getEmailTemplatesQuery } from './index.gql'; +import EmailTemplate from '../../../components/EmailTemplate'; -export default function Index({emailTemplates}) { - return ( - - - - - - {emailTemplates.map((e) => }/> )} - - - - ) +export default function Index({ emailTemplates }) { + return ( + + + + + + {emailTemplates.map((e) => } />)} + + + + ); } -export async function getServerSideProps({req, res, query}) { - const session = await getSession({req}); - const fetch = getFetcher(session); - if (!session) return {props: {}}; - const emailTemplateResults = await fetch(getEmailTemplatesQuery); - return { - props: { - emailTemplates: emailTemplateResults.clear.emailTemplates, - }, - }; +export async function getServerSideProps({ req, res, query }) { + const session = await getSession({ req }); + const fetch = getFetcher(session); + if (!session) return { props: {} }; + const emailTemplateResults = await fetch(getEmailTemplatesQuery); + return { + props: { + emailTemplates: emailTemplateResults.clear.emailTemplates, + }, + }; } - diff --git a/src/pages/admin/index.js b/src/pages/admin/index.js index 4612863..64f61ba 100644 --- a/src/pages/admin/index.js +++ b/src/pages/admin/index.js @@ -1,14 +1,14 @@ -import {Link} from '@codeday/topo/Atom'; +import { Link } from '@codeday/topo/Atom'; import Page from '../../components/Page'; export default function Index() { - return ( - -
    -
  • - Email templates -
  • -
-
- ); + return ( + +
    +
  • + Email templates +
  • +
+
+ ); } diff --git a/src/pages/api/auth/[...nextauth].js b/src/pages/api/auth/[...nextauth].js index 1f1777c..4056628 100644 --- a/src/pages/api/auth/[...nextauth].js +++ b/src/pages/api/auth/[...nextauth].js @@ -1,29 +1,29 @@ import NextAuth from 'next-auth'; -import Auth0Provider from "next-auth/providers/auth0" +import Auth0Provider from 'next-auth/providers/auth0'; import getConfig from 'next/config'; -import {generateToken} from '../../../token'; +import { generateToken } from '../../../token'; -const {serverRuntimeConfig} = getConfig(); +const { serverRuntimeConfig } = getConfig(); const options = { - secret: serverRuntimeConfig.appSecret, - providers: [ - Auth0Provider(serverRuntimeConfig.auth0), - ], - callbacks: { - jwt: async ({ token, user, profile }) => { - if (user) { - // This is bad but NextAuth requires it - token.user = profile; - } - return Promise.resolve(token); - }, - session: async ({ session, token }) => Promise.resolve({ - ...session, - ...await generateToken(token.user.nickname), - user: token.user, - }), + secret: serverRuntimeConfig.appSecret, + providers: [ + Auth0Provider(serverRuntimeConfig.auth0), + ], + callbacks: { + jwt: async ({ token, user, profile }) => { + if (user) { + // This is bad but NextAuth requires it + token.user = profile; + } + return Promise.resolve(token); }, + session: async ({ session, token }) => Promise.resolve({ + ...session, + ...await generateToken(token.user.nickname), + user: token.user, + }), + }, }; export default (req, res) => NextAuth(req, res, options); diff --git a/src/pages/events/[event]/advancedConfig.js b/src/pages/events/[event]/advancedConfig.js index 16e717a..77233d2 100644 --- a/src/pages/events/[event]/advancedConfig.js +++ b/src/pages/events/[event]/advancedConfig.js @@ -1,102 +1,105 @@ -import React from "react"; -import Page from "../../../components/Page"; -import Breadcrumbs from "../../../components/Breadcrumbs"; -import {Heading, Text} from "@codeday/topo/Atom" -import {getSession} from "next-auth/react"; -import {getFetcher} from "../../../fetch"; -import {UiInfo} from "@codeday/topocons/Icon" -import EditSpecificMetadata from "../../../components/forms/EditSpecificMetadata"; -import { SetEventMetadataMutation } from "../../../components/forms/EditSpecificMetadata.gql" -import { getEventAdvancedConfigQuery } from "./advancedConfig.gql" -export default function AdvancedConfig({event}) { - if (!event) return - return ( - - - {event.name} ~ Advanced Config - - {' '} - These settings tweak how other apps and sites display your event. They only need to be changed in rare - circumstances, so consult your CodeDay staff contact before making changes. - - - - - - - - - - ) +import React from 'react'; +import { Heading, Text } from '@codeday/topo/Atom'; +import { getSession } from 'next-auth/react'; +import { UiInfo } from '@codeday/topocons'; +import Page from '../../../components/Page'; +import Breadcrumbs from '../../../components/Breadcrumbs'; +import { getFetcher } from '../../../fetch'; +import EditSpecificMetadata from '../../../components/forms/EditSpecificMetadata'; +import { SetEventMetadataMutation } from '../../../components/forms/EditSpecificMetadata.gql'; +import { getEventAdvancedConfigQuery } from './advancedConfig.gql'; + +export default function AdvancedConfig({ event }) { + if (!event) return ; + return ( + + + {event.name} ~ Advanced Config + + {' '} + These settings tweak how other apps and sites display your event. They only need to be changed in rare + circumstances, so consult your CodeDay staff contact before making changes. + + + + + + + + + + ); } -export async function getServerSideProps({req, res, query: {event: eventId}}) { - const session = await getSession({req}) - const fetch = getFetcher(session); - if (!session) return {props: {}}; - const eventResults = await fetch(getEventAdvancedConfigQuery, {data: {id: eventId}}); - const event = eventResults?.clear?.event - if (!event) return { - redirect: { - destination: '/events', - permanent: false - } - } +export async function getServerSideProps({ req, res, query: { event: eventId } }) { + const session = await getSession({ req }); + const fetch = getFetcher(session); + if (!session) return { props: {} }; + const eventResults = await fetch(getEventAdvancedConfigQuery, { data: { id: eventId } }); + const event = eventResults?.clear?.event; + if (!event) { return { - props: { - event: event - } - } + redirect: { + destination: '/events', + permanent: false, + }, + }; + } + return { + props: { + event, + }, + }; } diff --git a/src/pages/events/[event]/eventRestrictions.js b/src/pages/events/[event]/eventRestrictions.js index 480d36b..ef1c918 100644 --- a/src/pages/events/[event]/eventRestrictions.js +++ b/src/pages/events/[event]/eventRestrictions.js @@ -1,45 +1,44 @@ import React from 'react'; -import Breadcrumbs from "../../../components/Breadcrumbs"; -import Masonry, {ResponsiveMasonry} from 'react-responsive-masonry'; -import {EventRestrictionPreview} from "../../../components/EventRestriction"; -import Page from "../../../components/Page" -import {Heading} from "@codeday/topo/Atom"; -import {getSession} from "next-auth/react"; -import {getFetcher} from "../../../fetch"; -import {GetEventRestrictionsQuery} from "./eventRestrictions.gql" -import LinkEventRestrictionsModal from "../../../components/LinkEventRestrictionsModal"; -import InfoBox from "../../../components/InfoBox"; +import Masonry, { ResponsiveMasonry } from 'react-responsive-masonry'; +import { Heading } from '@codeday/topo/Atom'; +import { getSession } from 'next-auth/react'; +import Breadcrumbs from '../../../components/Breadcrumbs'; +import { EventRestrictionPreview } from '../../../components/EventRestriction'; +import Page from '../../../components/Page'; +import { getFetcher } from '../../../fetch'; +import { GetEventRestrictionsQuery } from './eventRestrictions.gql'; +import LinkEventRestrictionsModal from '../../../components/LinkEventRestrictionsModal'; +import InfoBox from '../../../components/InfoBox'; -export default function EventRestrictions({event, restrictions}) { - const requiredRestrictions = event?.region?.localizationConfig?.requiredEventRestrictions?.items || []; - if (!event) return - return ( - - - {event.name} ~ Event Restrictions - - - - {[ - ...event.cmsEventRestrictions, - ...requiredRestrictions, - ].map((r) => )} - - - - ) +export default function EventRestrictions({ event, restrictions }) { + const requiredRestrictions = event?.region?.localizationConfig?.requiredEventRestrictions?.items || []; + if (!event) return ; + return ( + + + {event.name} ~ Event Restrictions + + + + {[ + ...event.cmsEventRestrictions, + ...requiredRestrictions, + ].map((r) => )} + + + + ); } -export async function getServerSideProps({req, res, query: {event: eventId}}) { - const session = await getSession({req}); - const fetch = getFetcher(session); - if (!session) return {props: {}}; - const eventResults = await fetch(GetEventRestrictionsQuery, {data: {id: eventId}}) - return { - props: { - event: eventResults.clear.event, - restrictions: eventResults.cms.eventRestrictions - } - } - +export async function getServerSideProps({ req, res, query: { event: eventId } }) { + const session = await getSession({ req }); + const fetch = getFetcher(session); + if (!session) return { props: {} }; + const eventResults = await fetch(GetEventRestrictionsQuery, { data: { id: eventId } }); + return { + props: { + event: eventResults.clear.event, + restrictions: eventResults.cms.eventRestrictions, + }, + }; } diff --git a/src/pages/events/[event]/index.js b/src/pages/events/[event]/index.js index 294b7ab..2cc7c80 100644 --- a/src/pages/events/[event]/index.js +++ b/src/pages/events/[event]/index.js @@ -1,135 +1,135 @@ import React from 'react'; -import {Button, Heading, Text, Link} from "@codeday/topo/Atom"; -import Masonry, {ResponsiveMasonry} from 'react-responsive-masonry'; -import * as Icon from '@codeday/topocons/Icon'; -import {getSession} from 'next-auth/react'; +import { + Button, Heading, Text, Link, +} from '@codeday/topo/Atom'; +import Masonry, { ResponsiveMasonry } from 'react-responsive-masonry'; +import { Eye, UiAdd } from '@codeday/topocons'; +import { getSession } from 'next-auth/react'; import Page from '../../../components/Page'; -import {getEventQuery} from './index.gql'; -import {getFetcher} from '../../../fetch'; +import { getEventQuery } from './index.gql'; +import { getFetcher } from '../../../fetch'; import Breadcrumbs from '../../../components/Breadcrumbs'; import VenueInfo from '../../../components/VenueInfo'; -import {CreateVenueModal} from '../../../components/forms/Venue'; +import { CreateVenueModal } from '../../../components/forms/Venue'; import Alert from '../../../components/Alert'; import Notes from '../../../components/forms/Notes'; import RegistrationsToggleWithChecklist from '../../../components/RegistrationsToggleWithChecklist'; import SponsorOverview from '../../../components/SponsorOverview'; import RegistrationGraph from '../../../components/RegistrationGraph'; -import {DeleteEventModal, UpdateEventModal} from '../../../components/forms/Event'; -import {SetEventNotesMutation} from '../../../components/forms/Notes.gql'; +import { DeleteEventModal, UpdateEventModal } from '../../../components/forms/Event'; +import { SetEventNotesMutation } from '../../../components/forms/Notes.gql'; import DaysUntilEvent from '../../../components/DaysUntilEvent'; -import {CreateSponsorModal} from '../../../components/forms/Sponsor'; -import {CreateScheduleItemModal} from '../../../components/forms/ScheduleItem'; +import { CreateSponsorModal } from '../../../components/forms/Sponsor'; +import { CreateScheduleItemModal } from '../../../components/forms/ScheduleItem'; import ScheduleBox from '../../../components/ScheduleBox'; -import TicketBox from "../../../components/TicketBox"; -import EventRestrictionBox from "../../../components/EventRestrictionBox"; -import InfoBox from "../../../components/InfoBox"; +import TicketBox from '../../../components/TicketBox'; +import EventRestrictionBox from '../../../components/EventRestrictionBox'; +import InfoBox from '../../../components/InfoBox'; import MetadataBox from '../../../components/MetadataBox'; - -export default function Event({event}) { - if (!event) return ; - return ( - - - - {event.name} ({event.displayDate}) - - - - {event.eventGroup.name} - - - - } - > - - - - +export default function Event({ event }) { + if (!event) return ; + return ( + + + + {event.name} ({event.displayDate}) + + + + {event.eventGroup.name} + + + + } + /> + + +   - - - } - > - - + + + )} + /> + } - > - - - + /> + +   - - - } - /> - - PROMOS + + + )} + /> + + PROMOS } - /> - - - - } - /> - - - - - - - - - Set metadata (advanced) - - - - - ); + /> + + + + )} + /> + + + + + + + + + Set metadata (advanced) + + + + + ); } -export async function getServerSideProps({req, res, query: {event: eventId}}) { - const session = await getSession({req}); - const fetch = getFetcher(session); - if (!session) return {props: {}}; - const eventResults = await fetch(getEventQuery, {data: {id: eventId}}); - const event = eventResults?.clear?.event - if (!event) return { - redirect: { - destination: `/events`, - permanent: false - } - } +export async function getServerSideProps({ req, res, query: { event: eventId } }) { + const session = await getSession({ req }); + const fetch = getFetcher(session); + if (!session) return { props: {} }; + const eventResults = await fetch(getEventQuery, { data: { id: eventId } }); + const event = eventResults?.clear?.event; + if (!event) { return { - props: { - event: event, - }, + redirect: { + destination: `/events`, + permanent: false, + }, }; + } + return { + props: { + event, + }, + }; } diff --git a/src/pages/events/[event]/notification.js b/src/pages/events/[event]/notification.js index 5582fd8..bcd7f44 100644 --- a/src/pages/events/[event]/notification.js +++ b/src/pages/events/[event]/notification.js @@ -1,89 +1,93 @@ -import React, { useState } from "react"; -import Page from "../../../components/Page"; -import Breadcrumbs from "../../../components/Breadcrumbs"; -import { useToasts } from "@codeday/topo/utils"; -import {Heading, Text, TextInput, Textarea, Checkbox, Button} from "@codeday/topo/Atom"; -import {getSession} from "next-auth/react"; -import {SendNotification, getEventQuery} from "./notification.gql" -import {useFetcher, getFetcher} from "../../../fetch"; +import React, { useState } from 'react'; +import { useToasts } from '@codeday/topo/utils'; +import { + Heading, Text, TextInput, Textarea, Checkbox, Button, +} from '@codeday/topo/Atom'; +import { getSession } from 'next-auth/react'; +import Breadcrumbs from '../../../components/Breadcrumbs'; +import Page from '../../../components/Page'; +import { SendNotification, getEventQuery } from './notification.gql'; +import { useFetcher, getFetcher } from '../../../fetch'; -export default function Notification({event}) { - const fetch = useFetcher(); - const [emailSubject, setEmailSubject] = useState(''); - const [emailBody, setEmailBody] = useState(''); - const [smsBody, setSmsBody] = useState(''); - const [guardian, setGuardian] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const { success, error } = useToasts(); +export default function Notification({ event }) { + const fetch = useFetcher(); + const [emailSubject, setEmailSubject] = useState(''); + const [emailBody, setEmailBody] = useState(''); + const [smsBody, setSmsBody] = useState(''); + const [guardian, setGuardian] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const { success, error } = useToasts(); - return ( - - - {event.name} ~ Send Notification - - To send only an email or SMS, leave the other options blank. Email body uses Markdown. - You can use {'{{'}ticket.id{'}}'} and {'{{'}to.name{'}}'} style templates. - - setEmailSubject(e.target.value)} - /> -