diff --git a/package-lock.json b/package-lock.json index 301f157..22d7dfc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11474,6 +11474,21 @@ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" }, + "qr.js": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz", + "integrity": "sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8=" + }, + "qrcode.react": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-1.0.0.tgz", + "integrity": "sha512-jBXleohRTwvGBe1ngV+62QvEZ/9IZqQivdwzo9pJM4LQMoCM2VnvNBnKdjvGnKyDZ/l0nCDgsPod19RzlPvm/Q==", + "requires": { + "loose-envify": "^1.4.0", + "prop-types": "^15.6.0", + "qr.js": "0.0.0" + } + }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", diff --git a/package.json b/package.json index 12392e0..006a14d 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "date-fns": "^2.11.0", "graphql": "^14.6.0", "moment": "^2.24.0", + "qrcode.react": "^1.0.0", "query-string": "^6.11.1", "react": "^16.13.1", "react-dom": "^16.13.1", diff --git a/src/App.js b/src/App.js index 6a67e01..6f42514 100644 --- a/src/App.js +++ b/src/App.js @@ -4,9 +4,8 @@ import { useQuery } from '@apollo/react-hooks'; import { makeStyles } from '@material-ui/core'; import { GET_ME } from './gql/users'; import { redirectToLogin } from './functions'; -import { Homepage } from './components/routes/homepage/Homepage'; import { Header, Loading } from './components/shared'; -import { UserProfile } from './components/routes/user-profile/UserProfile'; +import { Homepage, UserProfile, EventDetails } from './components/routes/'; const useStyles = makeStyles(theme => ({ root: { @@ -38,8 +37,9 @@ export const App = () => {
- } /> - } /> + + + diff --git a/src/components/routes/event-details/EventDescription.js b/src/components/routes/event-details/EventDescription.js new file mode 100644 index 0000000..9938ede --- /dev/null +++ b/src/components/routes/event-details/EventDescription.js @@ -0,0 +1,65 @@ +import React from 'react'; +import { + Container, + Typography, + makeStyles, + CardMedia +} from '@material-ui/core'; +import { getTimeDescription } from '../../../functions'; +import placeholder from '../../../assets/no_image_placeholder.png'; + +const useStyles = makeStyles(theme => ({ + root: { + display: 'grid', + gridTemplateColumns: '70% 30%', + maxHeight: 500, + padding: 0, + [theme.breakpoints.down('sm')]: { + gridTemplateColumns: '100%', + maxHeight: 'none' + } + }, + media: { + width: '100%', + paddingTop: '60%', + '&:hover': { + cursor: 'pointer' + } + }, + eventDetails: { + maxHeight: 500, + overflowY: 'scroll', + padding: `min(10%, ${theme.spacing(4)}px)` + }, + descriptionDetails: { + margin: `${theme.spacing(2)}px 0px` + } +})); + +export const EventDescription = ({ + event: { title, image_url, subscribers, start, end, description } +}) => { + const classes = useStyles(); + + return ( + + window.open(image_url, '_blank')} + /> + + + {title} + + + {getTimeDescription({ start, end })} + + + {description} + + + + ); +}; diff --git a/src/components/routes/event-details/EventDetail.js b/src/components/routes/event-details/EventDetail.js new file mode 100644 index 0000000..45b20da --- /dev/null +++ b/src/components/routes/event-details/EventDetail.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { Container, makeStyles, Card } from '@material-ui/core'; +import { EventDescription } from './EventDescription'; +import { EventToolbar } from './EventToolbar'; + +const useStyles = makeStyles(theme => ({ + root: { + padding: theme.spacing(5), + width: '100%' + }, + card: { + width: '100%' + } +})); + +export const EventDetail = ({ event, me }) => { + const classes = useStyles(); + + return ( + + + + + + + ); +}; diff --git a/src/components/routes/event-details/EventDetails.js b/src/components/routes/event-details/EventDetails.js new file mode 100644 index 0000000..1d1f708 --- /dev/null +++ b/src/components/routes/event-details/EventDetails.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { Switch, Route } from 'react-router-dom'; +import { EventDetail } from './EventDetail'; +import { Loading } from '../../shared'; +import { useDataFetching } from '../../../custom-hooks'; + +export const EventDetails = () => { + const { data, loading, error } = useDataFetching(); + + if (loading) return ; + if (error) console.log(error); + + const { events, me } = data; + + return ( + + {events.map(event => { + const { id } = event; + return ( + } + /> + ); + })} + + ); +}; diff --git a/src/components/routes/event-details/EventToolbar.js b/src/components/routes/event-details/EventToolbar.js new file mode 100644 index 0000000..bb51cb0 --- /dev/null +++ b/src/components/routes/event-details/EventToolbar.js @@ -0,0 +1,79 @@ +import React, { useState } from 'react'; +import { makeStyles, Container, Button } from '@material-ui/core'; +import { ShareEvent } from './share-event/ShareEvent'; +import { EventOrganiser } from './event-organiser/EventOrganiser'; +import { Modal } from '../../shared'; +import { useSubscribeMutations } from '../../../custom-hooks'; +import { createModalMessage, getSubscriptionStatus } from '../../../functions'; + +const useStyles = makeStyles(theme => ({ + root: { + padding: `${theme.spacing(2)}px 0px`, + display: 'grid', + gridTemplateColumns: '70% 30%', + alignItems: 'center', + [theme.breakpoints.down('xs')]: { + gridTemplateColumns: '100%' + } + }, + buttonsBar: { + padding: 0 + }, + subscribedButton: { + color: '#000', + backgroundColor: theme.palette.others.main, + '&:hover': { + backgroundColor: theme.palette.others.dark + } + } +})); + +export const EventToolbar = ({ event, me: { username } }) => { + const { id, organiser, subscribers } = event; + const classes = useStyles(); + + const subcriptionStatus = getSubscriptionStatus(subscribers, username); + const [isSubscribed, setIsSubscribed] = useState(subcriptionStatus); + const [modal, setModal] = useState({ + isOpen: false, + title: '' + }); + + const { + methods: { subscribeEvent, unsubscribeEvent }, + loading: subscribeMutationLoading, + error: { subscribeError, unsubscribeError } + } = useSubscribeMutations(); + + const onSubscribeButtonClicked = () => { + if (!isSubscribed) + subscribeEvent({ variables: { id } }) + .then(({ data }) => setIsSubscribed(true)) + .catch(err => setModal(createModalMessage('error'))); + else + unsubscribeEvent({ variables: { id } }) + .then(({ data }) => setIsSubscribed(false)) + .catch(err => setModal(createModalMessage('error'))); + }; + + if (subscribeError || unsubscribeError) + console.log({ subscribeError, unsubscribeError }); + + return ( + + window.location.reload()} /> + + + + + + + ); +}; diff --git a/src/components/routes/event-details/event-organiser/EventOrganiser.js b/src/components/routes/event-details/event-organiser/EventOrganiser.js new file mode 100644 index 0000000..54c9c3f --- /dev/null +++ b/src/components/routes/event-details/event-organiser/EventOrganiser.js @@ -0,0 +1,93 @@ +import React, { useState } from 'react'; +import { + Container, + Typography, + ListItem, + ListItemAvatar, + Avatar, + ListItemText, + makeStyles +} from '@material-ui/core'; +import { EventOrganiserInfo } from './EventOrganiserInfo'; +import { ComplexModal as EventOrganiserModal } from '../../../shared'; + +const useStyles = makeStyles(theme => ({ + root: { + padding: 0, + margin: `${theme.spacing(1)}px 0px`, + display: 'flex', + flexDirection: 'column' + }, + title: { + color: '#9e9e9e' + }, + organiser: { + padding: `${theme.spacing(1)}px 0px`, + width: 'fit-content' + }, + avatar: { + '&:hover': { + cursor: 'pointer' + } + }, + displayName: { + color: theme.palette.primary.dark, + fontWeight: 300, + '&:hover': { + cursor: 'pointer' + } + } +})); + +export const EventOrganiser = ({ + organiser: { first_name, last_name, username, image_url, email, phone } +}) => { + const classes = useStyles(); + + const defaultModalContent = { title: '', childComponent: <> }; + const [modal, setModal] = useState({ + isOpen: false, + modalContent: defaultModalContent + }); + + const displayName = `${first_name} ${last_name}`; + const modalContent = { + title: 'Organiser info', + childComponent: + }; + + const openModal = () => setModal({ isOpen: true, modalContent }); + + return ( + + + setModal({ isOpen: false, modalContent: defaultModalContent }) + } + /> + + organised by + + + + + + + + {displayName} + + + + + ); +}; diff --git a/src/components/routes/event-details/event-organiser/EventOrganiserInfo.js b/src/components/routes/event-details/event-organiser/EventOrganiserInfo.js new file mode 100644 index 0000000..4acb51c --- /dev/null +++ b/src/components/routes/event-details/event-organiser/EventOrganiserInfo.js @@ -0,0 +1,85 @@ +import React, { useState } from 'react'; +import { + Container, + List, + ListItem, + ListItemIcon, + Input, + makeStyles +} from '@material-ui/core'; +import { Email as EmailIcon, Phone as PhoneIcon } from '@material-ui/icons'; +import { Alert } from '../../../shared'; + +const useStyles = makeStyles(theme => ({ + root: { + padding: theme.spacing(1) + }, + iconItem: { + '&:hover': { + color: theme.palette.primary.main, + cursor: 'pointer' + } + }, + inputItem: { + color: theme.palette.primary.dark + } +})); + +export const EventOrganiserInfo = ({ organiserInfo: { email, phone } }) => { + const defaultAlertContent = { + isOpen: false, + alertContent: '' + }; + + const [alert, setAlert] = useState(defaultAlertContent); + const classes = useStyles(); + + const copyPhoneNumberToClipboard = () => { + const copyText = document.getElementById('phone-number'); + copyText.select(); + document.execCommand('copy'); + setAlert({ isOpen: true, alertContent: 'Copied to clipboard' }); + }; + + const onEmailClick = () => (window.location = `mailto:${email}`); + const onPhoneClick = () => copyPhoneNumberToClipboard(); + const listItems = [ + { + id: 'email-address', + icon: , + text: email, + onClick: onEmailClick + }, + { + id: 'phone-number', + icon: , + text: phone, + onClick: onPhoneClick + } + ]; + + return ( + + setAlert(defaultAlertContent)} + /> + + {listItems.map(({ id, icon, text, onClick }, index) => ( + + + {icon} + + + + ))} + + + ); +}; diff --git a/src/components/routes/event-details/share-event/ShareEvent.js b/src/components/routes/event-details/share-event/ShareEvent.js new file mode 100644 index 0000000..9be09c8 --- /dev/null +++ b/src/components/routes/event-details/share-event/ShareEvent.js @@ -0,0 +1,51 @@ +import React, { useState } from 'react'; +import { makeStyles, Button } from '@material-ui/core'; +import { ShareEventDetails } from './ShareEventDetails'; +import { ComplexModal as ShareEventModal } from '../../../shared'; + +const useStyles = makeStyles(theme => ({ + shareButton: { + marginTop: theme.spacing(1), + color: theme.palette.primary.light, + backgroundColor: theme.palette.background.default, + border: `1px solid ${theme.palette.primary.light}`, + '&:hover': { + color: '#fff', + backgroundColor: theme.palette.primary.light + } + } +})); + +export const ShareEvent = ({ event }) => { + const classes = useStyles(); + const defaultModalContent = { title: '', childComponent: <> }; + + const [modal, setModal] = useState({ + isOpen: false, + modalContent: defaultModalContent + }); + + const shareEventModalContent = ; + const modalContent = { + title: 'Share event', + childComponent: shareEventModalContent + }; + + return ( + <> + + setModal({ isOpen: false, modalContent: defaultModalContent }) + } + /> + + + ); +}; diff --git a/src/components/routes/event-details/share-event/ShareEventDetails.js b/src/components/routes/event-details/share-event/ShareEventDetails.js new file mode 100644 index 0000000..e9aec6f --- /dev/null +++ b/src/components/routes/event-details/share-event/ShareEventDetails.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { Container, makeStyles } from '@material-ui/core'; +import { ShareEventLink } from './ShareEventLink'; +import { ShareEventQRCode } from './ShareEventQRCode'; + +const useStyles = makeStyles(theme => ({ + root: { + padding: theme.spacing(1) + } +})); + +export const ShareEventDetails = ({ event }) => { + const classes = useStyles(); + + return ( + + + + + ); +}; diff --git a/src/components/routes/event-details/share-event/ShareEventLink.js b/src/components/routes/event-details/share-event/ShareEventLink.js new file mode 100644 index 0000000..511ec2a --- /dev/null +++ b/src/components/routes/event-details/share-event/ShareEventLink.js @@ -0,0 +1,61 @@ +import React, { useState } from 'react'; +import { + Container, + makeStyles, + OutlinedInput, + Tooltip +} from '@material-ui/core'; +import { Assignment as ClipboardIcon } from '@material-ui/icons'; +import { Alert } from '../../../shared'; + +const useStyles = makeStyles(theme => ({ + root: { + padding: 0, + display: 'grid', + gridTemplateColumns: '90% 10%', + justifyItems: 'center' + }, + clipboardIcon: { + height: '100%', + '&:hover': { + cursor: 'pointer' + } + } +})); + +export const ShareEventLink = () => { + const defaultAlertContent = { + isOpen: false, + alertContent: '' + }; + + const [alert, setAlert] = useState(defaultAlertContent); + const classes = useStyles(); + + const copyEventLinkToClipboard = () => { + const copyText = document.getElementById('event-link'); + copyText.select(); + document.execCommand('copy'); + setAlert({ isOpen: true, alertContent: 'Copied to clipboard' }); + }; + + return ( + + setAlert(defaultAlertContent)} + /> + + + copyEventLinkToClipboard()} + /> + + + ); +}; diff --git a/src/components/routes/event-details/share-event/ShareEventQRCode.js b/src/components/routes/event-details/share-event/ShareEventQRCode.js new file mode 100644 index 0000000..66aa64e --- /dev/null +++ b/src/components/routes/event-details/share-event/ShareEventQRCode.js @@ -0,0 +1,62 @@ +import React from 'react'; +import QRCode from 'qrcode.react'; +import { Container, makeStyles, Button } from '@material-ui/core'; + +const useStyles = makeStyles(theme => ({ + root: { + padding: 0, + display: 'grid', + justifyItems: 'center' + }, + qrCode: { + margin: `${theme.spacing(2)}px 0px`, + borderRadius: 5, + width: 256, + height: 256, + maxWidth: '70vw' + }, + saveButton: { + width: 256, + maxWidth: '70vw' + } +})); + +const downloadQRCode = ({ eventId }) => { + const img = document.createElement('img'); + const canvas = document.createElement('canvas'); + + // Get SVG data and convert it to base64 formst + const svg = document.getElementById('qr-code'); + const xml = new XMLSerializer().serializeToString(svg); + const svg64 = 'data:image/svg+xml;base64,' + btoa(xml); + + img.onload = () => { + canvas.getContext('2d').drawImage(img, 0, 0); + const link = document.createElement('a'); + link.download = `raven_${eventId}.png`; + link.href = canvas.toDataURL(); + link.click(); + }; + img.src = svg64; +}; + +export const ShareEventQRCode = ({ event: { id } }) => { + const classes = useStyles(); + + return ( + + + + + ); +}; diff --git a/src/components/routes/homepage/Events.js b/src/components/routes/homepage/Events.js index f28f289..bb2ba73 100644 --- a/src/components/routes/homepage/Events.js +++ b/src/components/routes/homepage/Events.js @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { MediaCard } from './MediaCard'; import { Container, Typography, makeStyles } from '@material-ui/core'; import { SearchBar } from './SearchBar'; -import { filterEvents, sortEvents } from '../../../functions'; +import { filterEvents, getSubscriptionStatus, sortEvents } from '../../../functions'; const useStyles = makeStyles(theme => ({ container: { @@ -35,11 +35,6 @@ export const Events = ({ events, me: { username } }) => { const filteredEvents = filterEvents({ events, filter }); const sortedEvents = sortEvents({ events: [...filteredEvents], sortParam }); - const getSubscriptionStatus = ({ subscribers }) => - subscribers - .map(({ username: subscribersUsername }) => subscribersUsername) - .includes(username); - return ( { ); })} diff --git a/src/components/routes/homepage/MediaCard.js b/src/components/routes/homepage/MediaCard.js index ddd6ef3..c633e9a 100644 --- a/src/components/routes/homepage/MediaCard.js +++ b/src/components/routes/homepage/MediaCard.js @@ -9,6 +9,7 @@ import { Typography, makeStyles } from '@material-ui/core'; +import { Link } from 'react-router-dom'; import placeholder from '../../../assets/no_image_placeholder.png'; import { useSubscribeMutations } from '../../../custom-hooks'; import { Modal, SubscribersList } from '../../shared'; @@ -57,7 +58,7 @@ const useStyles = makeStyles(theme => ({ export const MediaCard = ({ event: { id, title, start, venue, image_url, subscribers }, isEventSubscribed, - disableMutation + disableCard }) => { const [elevation, setElevation] = useState(1); const [isSubscribed, setIsSubscribed] = useState(isEventSubscribed); @@ -100,6 +101,8 @@ export const MediaCard = ({ className={classes.media} image={image_url ? image_url : placeholder} title={title} + component={Link} + to={disableCard ? '#' : `/event/${id}`} /> @@ -107,7 +110,7 @@ export const MediaCard = ({ className={isSubscribed ? classes.subscribedButton : ''} size="small" onClick={() => onSubscribeButtonClicked()} - disabled={disableMutation || subscribeMutationLoading} + disabled={disableCard || subscribeMutationLoading} > {isSubscribed ? 'Subscribed' : 'Subscribe'} diff --git a/src/components/routes/homepage/SearchBar.js b/src/components/routes/homepage/SearchBar.js index 91a7f9b..f0568fc 100644 --- a/src/components/routes/homepage/SearchBar.js +++ b/src/components/routes/homepage/SearchBar.js @@ -19,7 +19,7 @@ const useStyles = makeStyles(theme => ({ gridGap: theme.spacing(1), alignItems: 'center' }, - searchBar: { + searchInput: { width: 'min(100%, 300px)', color: theme.palette.primary.main }, @@ -43,13 +43,19 @@ export const SearchBar = ({ setFilter, sortParam, setSortParam }) => { return ( - } - onChange={({ target: { value } }) => setFilter(value)} - /> - + + } + onChange={({ target: { value } }) => setFilter(value)} + /> + + Sort by diff --git a/src/components/routes/homepage/event-form/EventForm.js b/src/components/routes/homepage/event-form/EventForm.js index 8b03aac..3c309f8 100644 --- a/src/components/routes/homepage/event-form/EventForm.js +++ b/src/components/routes/homepage/event-form/EventForm.js @@ -14,7 +14,7 @@ import { EventTimePicker } from './EventTimePicker'; import { ImagePicker } from './ImagePicker'; import { MediaCard } from '../MediaCard'; import { Modal } from '../../../shared'; -import { validateEvent } from '../../../../functions/validateEvent'; +import { validateEvent } from '../../../../functions'; import imagePlaceholder from '../../../../assets/no_image_placeholder.png'; const useStyles = makeStyles(theme => ({ @@ -145,7 +145,7 @@ export const EventForm = ({ onFormSubmit }) => { diff --git a/src/components/routes/index.js b/src/components/routes/index.js new file mode 100644 index 0000000..197bc13 --- /dev/null +++ b/src/components/routes/index.js @@ -0,0 +1,5 @@ +import { Homepage } from './homepage/Homepage'; +import { UserProfile } from './user-profile/UserProfile'; +import { EventDetails } from './event-details/EventDetails'; + +export { Homepage, UserProfile, EventDetails }; diff --git a/src/components/shared/Alert.js b/src/components/shared/Alert.js new file mode 100644 index 0000000..0cc3530 --- /dev/null +++ b/src/components/shared/Alert.js @@ -0,0 +1,29 @@ +import React from 'react'; +import { Snackbar, IconButton, Slide } from '@material-ui/core'; +import { Close as CloseIcon } from '@material-ui/icons'; + +const TransitionDown = props => ; + +export const Alert = ({ alertDetails: { isOpen, alertContent }, onClose }) => ( + + + + } + /> +); diff --git a/src/components/shared/subscribers/SubscribersModal.js b/src/components/shared/ComplexModal.js similarity index 78% rename from src/components/shared/subscribers/SubscribersModal.js rename to src/components/shared/ComplexModal.js index 1f85745..7789ee0 100644 --- a/src/components/shared/subscribers/SubscribersModal.js +++ b/src/components/shared/ComplexModal.js @@ -1,16 +1,17 @@ -import React from 'react'; +import React, { forwardRef } from 'react'; import { Typography, makeStyles, Dialog, DialogTitle, - DialogContent + DialogContent, + Slide } from '@material-ui/core'; const useStyles = makeStyles(theme => ({ root: { height: 'fit-content', - marginTop: '15%' + marginTop: '10%' }, title: { color: theme.palette.primary.dark, @@ -24,7 +25,11 @@ const useStyles = makeStyles(theme => ({ } })); -export const SubscribersModal = ({ +const Transition = forwardRef((props, ref) => ( + +)); + +export const ComplexModal = ({ modalDetails: { isOpen, modalContent }, onClose }) => { @@ -39,6 +44,7 @@ export const SubscribersModal = ({ onClose={onClose} fullWidth maxWidth="xs" + TransitionComponent={Transition} className={classes.root} > ({ subscribersCount: { diff --git a/src/components/shared/subscribers/index.js b/src/components/shared/subscribers/index.js index 416e27c..18fa3eb 100644 --- a/src/components/shared/subscribers/index.js +++ b/src/components/shared/subscribers/index.js @@ -1,5 +1,4 @@ import { SubscribersList } from './SubscribersList'; import { SubscribersDetails } from './SubscribersDetails'; -import { SubscribersModal } from './SubscribersModal'; -export { SubscribersList, SubscribersDetails, SubscribersModal }; +export { SubscribersList, SubscribersDetails }; diff --git a/src/functions/filterEvents.js b/src/functions/events/filterEvents.js similarity index 100% rename from src/functions/filterEvents.js rename to src/functions/events/filterEvents.js diff --git a/src/functions/events/getSubscriptionStatus.js b/src/functions/events/getSubscriptionStatus.js new file mode 100644 index 0000000..238e0a3 --- /dev/null +++ b/src/functions/events/getSubscriptionStatus.js @@ -0,0 +1,2 @@ +export const getSubscriptionStatus = (subscribers, username) => + subscribers.map(({ username }) => username).includes(username); diff --git a/src/functions/events/index.js b/src/functions/events/index.js new file mode 100644 index 0000000..1699faa --- /dev/null +++ b/src/functions/events/index.js @@ -0,0 +1,11 @@ +import { filterEvents, selectUserEvents, sortEvents } from './filterEvents'; +import { validateEvent } from './validateEvent'; +import { getSubscriptionStatus } from './getSubscriptionStatus'; + +export { + filterEvents, + selectUserEvents, + sortEvents, + validateEvent, + getSubscriptionStatus +}; diff --git a/src/functions/quickSort.js b/src/functions/events/quickSort.js similarity index 100% rename from src/functions/quickSort.js rename to src/functions/events/quickSort.js diff --git a/src/functions/validateEvent.js b/src/functions/events/validateEvent.js similarity index 100% rename from src/functions/validateEvent.js rename to src/functions/events/validateEvent.js diff --git a/src/functions/getTimeDescription.js b/src/functions/getTimeDescription.js new file mode 100644 index 0000000..787deb8 --- /dev/null +++ b/src/functions/getTimeDescription.js @@ -0,0 +1,8 @@ +import moment from 'moment'; + +export const getTimeDescription = ({ start, end }) => + moment(start).isSame(moment(end), 'd') + ? `${moment(start).format('ll')}, ${moment(start).format('LT')} - ${moment( + end + ).format('LT')}` + : `${moment(start).format('lll')} - ${moment(end).format('lll')}`; diff --git a/src/functions/index.js b/src/functions/index.js index 326a2c5..c907cac 100644 --- a/src/functions/index.js +++ b/src/functions/index.js @@ -1,7 +1,13 @@ +import { + filterEvents, + selectUserEvents, + sortEvents, + validateEvent, + getSubscriptionStatus +} from './events'; import { createModalMessage } from './createModalMessage'; -import { filterEvents, selectUserEvents, sortEvents } from './filterEvents'; import { redirectToLogin } from './redirectToLogin'; -import { validateEvent } from './validateEvent'; +import { getTimeDescription } from './getTimeDescription'; export { createModalMessage, @@ -9,5 +15,7 @@ export { validateEvent, filterEvents, selectUserEvents, - sortEvents + sortEvents, + getSubscriptionStatus, + getTimeDescription }; diff --git a/src/gql/events.js b/src/gql/events.js index 5e6f865..2cf110a 100644 --- a/src/gql/events.js +++ b/src/gql/events.js @@ -7,7 +7,11 @@ const GET_ALL_EVENTS = gql` organiser { id username + first_name + last_name + image_url email + phone } title start