Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add event details page #41

Closed
wants to merge 13 commits into from
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
8 changes: 4 additions & 4 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -38,8 +37,9 @@ export const App = () => {
<Router>
<Header me={me} />
<Switch>
<Route path="/user" component={() => <UserProfile />} />
<Route exact path="/" component={() => <Homepage />} />
<Route exact path="/" component={Homepage} />
<Route exact path="/user" component={UserProfile} />
<Route path="/event" component={EventDetails} />
</Switch>
</Router>
</div>
Expand Down
65 changes: 65 additions & 0 deletions src/components/routes/event-details/EventDescription.js
Original file line number Diff line number Diff line change
@@ -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 (
<Container className={classes.root}>
<CardMedia
className={classes.media}
image={image_url ? image_url : placeholder}
title={title}
onClick={() => window.open(image_url, '_blank')}
/>
<Container className={classes.eventDetails}>
<Typography variant="h4" className={classes.descriptionDetails}>
{title}
</Typography>
<Typography variant="body1" className={classes.descriptionDetails}>
{getTimeDescription({ start, end })}
</Typography>
<Typography variant="body1" className={classes.descriptionDetails}>
{description}
</Typography>
</Container>
</Container>
);
};
27 changes: 27 additions & 0 deletions src/components/routes/event-details/EventDetail.js
Original file line number Diff line number Diff line change
@@ -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 (
<Container className={classes.root}>
<Card className={classes.card}>
<EventDescription event={event} />
</Card>
<EventToolbar event={event} me={me} />
</Container>
);
};
30 changes: 30 additions & 0 deletions src/components/routes/event-details/EventDetails.js
Original file line number Diff line number Diff line change
@@ -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 <Loading />;
if (error) console.log(error);

const { events, me } = data;

return (
<Switch>
{events.map(event => {
const { id } = event;
return (
<Route
exact
path={`/event/${id}`}
key={id}
component={() => <EventDetail event={event} me={me} />}
/>
);
})}
</Switch>
);
};
79 changes: 79 additions & 0 deletions src/components/routes/event-details/EventToolbar.js
Original file line number Diff line number Diff line change
@@ -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 (
<Container className={classes.root}>
<Modal modalDetails={modal} onClose={() => window.location.reload()} />
<EventOrganiser organiser={organiser} />
<Container className={classes.buttonsBar}>
<Button
className={isSubscribed ? classes.subscribedButton : ''}
fullWidth
onClick={() => onSubscribeButtonClicked()}
disabled={subscribeMutationLoading}
>
{isSubscribed ? 'Subscribed' : 'Subscribe'}
</Button>
<ShareEvent event={event} />
</Container>
</Container>
);
};
Original file line number Diff line number Diff line change
@@ -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: <EventOrganiserInfo organiserInfo={{ email, phone }} />
};

const openModal = () => setModal({ isOpen: true, modalContent });

return (
<Container className={classes.root}>
<EventOrganiserModal
modalDetails={modal}
onClose={() =>
setModal({ isOpen: false, modalContent: defaultModalContent })
}
/>
<Typography variant="h6" className={classes.title}>
organised by
</Typography>
<ListItem className={classes.organiser}>
<ListItemAvatar>
<Avatar
alt={username}
src={image_url}
onClick={openModal}
className={classes.avatar}
/>
</ListItemAvatar>
<ListItemText>
<Typography
variant="subtitle1"
className={classes.displayName}
onClick={openModal}
>
{displayName}
</Typography>
</ListItemText>
</ListItem>
</Container>
);
};
Loading