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