Events Client Module moved to old repos

This commit is contained in:
Luis Fernando Molina committed 2020-11-20 19:52:31 +01:00
1 parent 3e036d06a2
commit 8ff71c6daf
87 files changed

No files matched your search

@@ -0,0 +1,18 @@
import React from 'react';
import Typography from '@material-ui/core/Typography';
const BannerTopBar = ({
size,
backgroundUrl,
title,
text,
}) => (
<div className={`bannerTopBar ${size}`} style={backgroundUrl ? { backgroundImage: `url(${backgroundUrl})` } : {}}>
<div className='caption'>
<Typography className='title' variant='h1' align='center'>{title}</Typography>
<Typography className='text' variant='h2' align='center'>{text}</Typography>
</div>
</div>
);
export default BannerTopBar;
@@ -0,0 +1,111 @@
import React from 'react';
import {
TextField,
Button,
FormGroup,
Typography,
Grid,
} from '@material-ui/core';
import {
ChevronLeft,
ChevronRight,
} from '@material-ui/icons';
import { DateTimePicker } from 'material-ui-pickers';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class Basic extends React.Component {
render() {
const {
classes, event, edit, create,
} = this.props;
return (
<React.Fragment>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
These are the basic information you need to input in order to create an event.
There might be some heavy changes in the near future as the application is still at a very early stage.
</Typography>
<TextField
label='Public id'
value='Your public ID will be generated automatically'
className={classes.inputField}
disabled
/>
<TextField
label='Title'
value={event.title}
className={classes.inputField}
onChange={newVal => edit('title', newVal.target.value)}
/>
<TextField
label='Subtitle'
value={event.subtitle}
className={classes.inputField}
onChange={newVal => edit('subtitle', newVal.target.value)}
/>
<TextField
multiline
label='Description'
value={event.description}
className={classes.inputField}
onChange={newVal => edit('description', newVal.target.value)}
/>
<FormGroup row className={classes.inputField}>
<Grid container justify='space-around' >
<Grid item>
<DateTimePicker
autoOk
disablePast
format="DD' at 'HH:mm"
ampm={false}
showTabs={false}
leftArrowIcon={<ChevronLeft />}
rightArrowIcon={<ChevronRight />}
value={event.startDatetime}
helperText='Competition start date'
onChange={newVal => edit('startDatetime', newVal)}
/>
</Grid>
<Grid item>
<DateTimePicker
autoOk
disablePast
format="DD' at 'HH:mm"
ampm={false}
showTabs={false}
leftArrowIcon={<ChevronLeft />}
rightArrowIcon={<ChevronRight />}
value={event.endDatetime}
helperText='Competition ending date'
onChange={newVal => edit('endDatetime', newVal)}
/>
</Grid>
</Grid>
</FormGroup>
<Grid container justify='center' >
<Grid item>
<Button
className={classes.bottomButton}
variant='contained'
color='secondary'
onClick={() => edit('value', 1)}
>
Go to technical tab
</Button>
<Button className={classes.bottomButton} onClick={() => create()} variant='contained' color='secondary'>
Or Create event
</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
}
export default withStyles(styles)(Basic);
@@ -0,0 +1,27 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class PresentationPage extends React.Component {
render() {
const { classes } = this.props;
return (
<React.Fragment>
<Typography
className={classes.title}
variant='h4'
align='center'
color='textPrimary'
gutterBottom
>
PresentationPage
</Typography>
</React.Fragment>
);
}
}
export default withStyles(styles)(PresentationPage);
@@ -0,0 +1,27 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class TeamsServer extends React.Component {
render() {
const { classes } = this.props;
return (
<React.Fragment>
<Typography
className={classes.title}
variant='h4'
align='center'
color='textPrimary'
gutterBottom
>
TeamsServer
</Typography>
</React.Fragment>
);
}
}
export default withStyles(styles)(TeamsServer);
@@ -0,0 +1,78 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
import { Mutation } from 'react-apollo';
import { getOptionsCalls } from '../../../../../../GraphQL/Calls/index';
class New extends React.Component {
constructor() {
super();
this.state = { name: '' };
}
render() {
const { name } = this.state;
const { closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='createFormula-dialog-title'
>
<DialogTitle id='createFormula-dialog-title'>
Create a new formula
</DialogTitle>
<DialogContent>
<DialogContentText>
At least for now, all the formulas are publically available, creating it here will let you select it in the select element.
</DialogContentText>
<Mutation mutation={getOptionsCalls.EVENTS_CREATEFORMULA}
update={(store, { data }) => {
const { events_Formulas: formulas } = store.readQuery({
query: getOptionsCalls.EVENTS_FORMULAS,
});
store.writeQuery({
query: getOptionsCalls.EVENTS_FORMULAS,
data: { events_Formulas: formulas.concat([data.events_CreateFormula]) },
});
closeDialogs();
}
}
>
{createFormula => (
<form
onSubmit={(e) => {
e.preventDefault();
createFormula({
variables: {
formula: { name },
},
});
}}
>
<TextField
label='Name'
value={name}
onChange={e => this.setState({ name: e.target.value })}
fullWidth
/>
<Button type='submit' variant='contained' color='secondary'>Create a new formula</Button>
</form>
)}
</Mutation>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,5 @@
import New from './New';
export {
New,
};
@@ -0,0 +1,108 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
import { Mutation } from 'react-apollo';
import { getOptionsCalls } from '../../../../../../GraphQL/Calls/index';
class New extends React.Component {
constructor() {
super();
this.state = {
name: '',
host: '',
repo: '',
moduleName: '',
};
}
render() {
const {
name, host, repo, moduleName,
} = this.state;
const { closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='createPlotter-dialog-title'
>
<DialogTitle id='createPlotter-dialog-title'>
Create a new plotter
</DialogTitle>
<DialogContent>
<DialogContentText>
At least for now, all the plotters are publically available, creating it here will let you select it in the select element.
</DialogContentText>
<Mutation mutation={getOptionsCalls.EVENTS_CREATEPLOTTER}
update={(store, { data }) => {
const { events_Plotters: plotters } = store.readQuery({
query: getOptionsCalls.EVENTS_PLOTTERS,
});
store.writeQuery({
query: getOptionsCalls.EVENTS_PLOTTERS,
data: { events_Plotters: plotters.concat([data.events_CreatePlotter]) },
});
closeDialogs();
}
}
>
{createPlotter => (
<form
onSubmit={(e) => {
e.preventDefault();
createPlotter({
variables: {
plotter: {
name,
host,
repo,
moduleName,
},
},
});
}}
>
<TextField
label='Name'
value={name}
onChange={e => this.setState({ name: e.target.value })}
fullWidth
/>
<TextField
label='Host'
value={host}
onChange={e => this.setState({ host: e.target.value })}
fullWidth
/>
<TextField
label='Repository'
value={repo}
onChange={e => this.setState({ repo: e.target.value })}
fullWidth
/>
<TextField
label='Module Name'
value={moduleName}
onChange={e => this.setState({ moduleName: e.target.value })}
fullWidth
/>
<Button type='submit' variant='contained' color='secondary'>Create a new plotter</Button>
</form>
)}
</Mutation>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,5 @@
import New from './New';
export {
New,
};
@@ -0,0 +1,72 @@
import React from 'react';
import {
Paper,
Grid,
Typography,
} from '@material-ui/core';
import {
SortableContainer,
SortableElement,
SortableHandle,
} from 'react-sortable-hoc';
const DragHandle = SortableHandle(() => <div className='dragHandle' />);
const SortableItem = SortableElement(({ value, deletePrize, index }) => (
<div className='sortableListItem'>
<Grid container spacing={16}>
<Grid item>
<DragHandle />
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={16}>
<Typography gutterBottom variant="subtitle1">
{value.from}{value.to}{value.additional}{value.amount}{value.asset}
</Typography>
<Typography color="textSecondary">
</Typography>
</Grid>
<Grid item>
<Typography style={{ cursor: 'pointer' }} onClick={() => deletePrize(index)} >Remove</Typography>
</Grid>
</Grid>
</Grid>
</div>
));
const SortableList = SortableContainer(({ items, deletePrize }) => (
<div className='sortableList'>
{items.map((value, index) => (
<SortableItem key={`prize-${index}`} index={index} value={value} deletePrize={deleteId => deletePrize(deleteId)} />
))}
</div>
));
class List extends React.Component {
onSortEnd = ({ oldIndex, newIndex }) => {
const newPrizes = this.props.prizes.slice(0);
newPrizes.splice(newIndex, 0, newPrizes.splice(oldIndex, 1)[0]);
this.props.edit(newPrizes);
}
deletePrize = (deletedIndex) => {
const newPrizes = this.props.prizes.slice(0);
newPrizes.splice(deletedIndex, 1);
this.props.edit(newPrizes);
}
render() {
return (
<Paper>
<SortableList
items={this.props.prizes}
onSortEnd={this.onSortEnd}
useDragHandle={true}
deletePrize={deleteId => this.deletePrize(deleteId)}
/>
</Paper>
);
}
}
export default List;
@@ -0,0 +1,106 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
class New extends React.Component {
constructor() {
super();
this.state = {
additional: '',
amount: 0,
asset: '',
};
}
render() {
const {
from, to, additional, amount, asset,
} = this.state;
const { addPrize, closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='addPrize-dialog-title'
>
<DialogContent>
<DialogContentText>
Prizes are define textually only. In case of infringement, contact us.
</DialogContentText>
<form
onSubmit={(e) => {
e.preventDefault();
addPrize({
from,
to,
additional,
amount,
asset,
});
}}
>
<DialogTitle>
Conditions :
</DialogTitle>
<DialogContentText>
Examples :
If you want to make a price for the best bot only, you set both from and to rank to 1.
If you want the rest of the top 10 to get a price, you add a new price with from rank set to 2 and to rank set to 10.
Caution :
- Leaving &quot;from rank&quot; empty considers it to 0.
- Leaving &quot;to rank&quot; empty considers it as infinite
- Prizes are define in an additive manner, meaning that if a team qualifies for two prices, it gets both.
- Additional allows you to write addionnal textual condition, like &quot;positive ROI only&quot; for example.
</DialogContentText>
<TextField
label='From rank'
value={from}
onChange={e => this.setState({ from: e.target.value })}
type="number"
/>
<TextField
label='To rank'
value={to}
onChange={e => this.setState({ to: e.target.value })}
type="number"
/>
<TextField
label='Additional'
value={additional}
onChange={e => this.setState({ additional: e.target.value })}
fullWidth
/>
<DialogContentText>
Pool :
</DialogContentText>
<DialogContentText>
Here you define the pool, the amount is a number whereas asset is a text. For example 1BTC, 200$, or whatever.
</DialogContentText>
<TextField
label='Amount'
value={amount}
onChange={e => this.setState({ amount: e.target.value })}
type="number"
/>
<TextField
label='Asset'
value={asset}
onChange={e => this.setState({ asset: e.target.value })}
/>
<Button type='submit' variant='contained' color='secondary'>Create a new prize</Button>
</form>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,7 @@
import List from './List';
import New from './New';
export {
List,
New,
};
@@ -0,0 +1,73 @@
import React from 'react';
import {
Paper,
Grid,
Typography,
} from '@material-ui/core';
import {
SortableContainer,
SortableElement,
SortableHandle,
} from 'react-sortable-hoc';
const DragHandle = SortableHandle(() => <div className='dragHandle' />);
const SortableItem = SortableElement(({ value, deleteRule, index }) => (
<div className='sortableListItem'>
<Grid container spacing={16}>
<Grid item>
<DragHandle />
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={16}>
<Typography gutterBottom variant="subtitle1">
{value.title}
</Typography>
<Typography color="textSecondary">
{value.description}
</Typography>
</Grid>
<Grid item>
<Typography style={{ cursor: 'pointer' }} onClick={() => deleteRule(index)} >Remove</Typography>
</Grid>
</Grid>
</Grid>
</div>
));
const SortableList = SortableContainer(({ items, deleteRule }) => (
<div className='sortableList'>
{items.map((value, index) => (
<SortableItem key={`rule-${index}`} index={index} value={value} deleteRule={deleteId => deleteRule(deleteId)} />
))}
</div>
));
class List extends React.Component {
onSortEnd = ({ oldIndex, newIndex }) => {
const newRules = this.props.rules.slice(0);
newRules.splice(newIndex, 0, newRules.splice(oldIndex, 1)[0]);
this.props.edit(newRules);
}
deleteRule = (deletedIndex) => {
const newRules = this.props.rules.slice(0);
newRules.splice(deletedIndex, 1);
this.props.edit(newRules);
}
render() {
return (
<Paper>
<SortableList
items={this.props.rules}
onSortEnd={this.onSortEnd}
useDragHandle={true}
deleteRule={deleteId => this.deleteRule(deleteId)}
/>
</Paper>
);
}
}
export default List;
@@ -0,0 +1,68 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
class New extends React.Component {
constructor() {
super();
this.state = {
title: '',
description: '',
};
}
render() {
const {
title, description,
} = this.state;
const { addRule, closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='addRule-dialog-title'
>
<DialogTitle id='addRule-dialog-title'>
Create a new rule
</DialogTitle>
<DialogContent>
<DialogContentText>
Rules are define textually only. In case of infringement, contact us.
</DialogContentText>
<form
onSubmit={(e) => {
e.preventDefault();
addRule(
title,
description,
);
}}
>
<TextField
label='Title'
value={title}
onChange={e => this.setState({ title: e.target.value })}
fullWidth
/>
<TextField
label='Description'
value={description}
onChange={e => this.setState({ description: e.target.value })}
fullWidth
/>
<Button type='submit' variant='contained' color='secondary'>Create a new rule</Button>
</form>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,7 @@
import List from './List';
import New from './New';
export {
List,
New,
};
@@ -0,0 +1,196 @@
import React from 'react';
import { Query } from 'react-apollo';
import {
Typography,
FormControl,
InputLabel,
Input,
Select,
FormHelperText,
MenuItem,
Grid,
Button,
} from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../../styles';
import { getOptionsCalls } from '../../../../../GraphQL/Calls/index';
import { List as RulesList, New as NewRule } from './Rules';
import { List as PrizesList, New as NewPrize } from './Prizes';
import { New as NewPlotter } from './Plotter';
import { New as NewFormula } from './Formula';
class Technical extends React.Component {
constructor(props) {
super(props);
this.state = {
isNewFormulaOpen: false,
isNewPlotterOpen: false,
isNewRuleOpen: false,
isNewPrizeOpen: false,
};
}
addRule = (title, description) => {
this.props.edit('rules', [...this.props.event.rules, {
title,
description,
}]);
this.closeDialogs();
}
addPrize = (prize) => {
this.props.edit('prizes', [...this.props.event.prizes, prize]);
this.closeDialogs();
}
closeDialogs = () => {
this.setState({
isNewFormulaOpen: false,
isNewPlotterOpen: false,
isNewRuleOpen: false,
isNewPrizeOpen: false,
});
}
render() {
const {
classes, event, edit, create,
} = this.props;
const {
isNewPlotterOpen, isNewFormulaOpen, isNewRuleOpen, isNewPrizeOpen,
} = this.state;
return (
<React.Fragment>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
Select the formula and the plotter you want to use, you can also create your own with the corresponding button.
</Typography>
<FormControl className={classes.inputField}>
<InputLabel shrink htmlFor='select'>
Select the formula
</InputLabel>
<Query query={getOptionsCalls.EVENTS_FORMULAS} >
{({ loading, error, data }) => {
if (loading) {
return (
<Select
value='loading'
input={<Input />}
displayEmpty
className={classes.selectEmpty}
disabled
>
<MenuItem key='1' value='loading'>Loading possibilities...</MenuItem>
</Select>
);
}
if (error) return `Error! ${error.message}`;
const selects = data.events_Formulas.map((formula, index) => (
<MenuItem key={index} value={formula.id}>{formula.name}</MenuItem>
));
return (
<React.Fragment>
<Select
value={event.formulaId}
input={<Input />}
displayEmpty
className={classes.selectEmpty}
onChange={newVal => edit('formulaId', newVal.target.value)}
>
{selects}
</Select>
{ isNewFormulaOpen ? <NewFormula closeDialogs={() => this.closeDialogs()} /> : ''}
</React.Fragment>
);
}}
</Query>
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewFormulaOpen: true }); }}>
To create a new formula, click here
</FormHelperText>
</FormControl>
<FormControl className={classes.inputField}>
<InputLabel shrink htmlFor='select'>
Select the Plotter
</InputLabel>
<Query query={getOptionsCalls.EVENTS_PLOTTERS} >
{({ loading, error, data }) => {
if (loading) {
return (
<Select
value='loading'
input={<Input />}
displayEmpty
className={classes.selectEmpty}
disabled
>
<MenuItem key='1' value='loading'>Loading possibilities...</MenuItem>
</Select>
);
}
if (error) return `Error! ${error.message}`;
const selects = data.events_Plotters.map((plotter, index) => (
<MenuItem key={index} value={plotter.id}>{plotter.name}</MenuItem>
));
return (
<React.Fragment>
<Select
value={event.plotterId}
input={<Input />}
displayEmpty
className={classes.selectEmpty}
onChange={newVal => edit('plotterId', newVal.target.value)}
>
{selects}
</Select>
{ isNewPlotterOpen ? <NewPlotter closeDialogs={() => this.closeDialogs()} /> : ''}
</React.Fragment>
);
}}
</Query>
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewPlotterOpen: true }); }} >
To create a new plotter, click here
</FormHelperText>
</FormControl>
<FormControl className={classes.inputField}>
<Typography variant='h5'>
Define the rules of your event.
</Typography>
<RulesList rules={event.rules} edit={newVal => edit('rules', newVal)} />
{ isNewRuleOpen
? <NewRule closeDialogs={() => this.closeDialogs()} addRule={(title, description) => this.addRule(title, description)} />
: ''}
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewRuleOpen: true }); }} >
To add a new rule, click here
</FormHelperText>
</FormControl>
<FormControl className={classes.inputField}>
<Typography variant='h5'>
Define the prizes of your event.
</Typography>
<PrizesList prizes={event.prizes} edit={newVal => edit('prizes', newVal)} />
{ isNewPrizeOpen
? <NewPrize closeDialogs={() => this.closeDialogs()} addPrize={prize => this.addPrize(prize)} />
: ''}
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewPrizeOpen: true }); }} >
To add a new prize, click here
</FormHelperText>
</FormControl>
<Grid container justify='center' >
<Grid item>
<Button className={classes.bottomButton} onClick={() => create()} variant='contained' color='secondary'>
Create the event
</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
}
export default withStyles(styles)(Technical);
@@ -0,0 +1,11 @@
import Basic from './Basic';
import PresentationPage from './PresentationPage';
import TeamsServer from './TeamsServer';
import Technical from './Technical';
export {
Basic,
PresentationPage,
TeamsServer,
Technical,
};
@@ -0,0 +1,212 @@
import React from 'react';
import { Mutation } from 'react-apollo';
import { DateTime } from 'luxon';
import {
Paper,
Typography,
AppBar,
Tabs,
Tab,
} from '@material-ui/core';
import {
Face as BasicIcon,
Alarm as TechnicalIcon,
Group as TeamAndServerIcon,
PresentToAll as PresentationIcon,
} from '@material-ui/icons';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles';
import BannerTopBar from '../../BannerTopBar';
import {
Basic,
PresentationPage,
TeamsServer,
Technical,
} from './Tabs';
import { hostedEventsCalls } from '../../../GraphQL/Calls';
function TabContainer(props) {
return (
<Typography component='div' style={{ padding: 8 * 3 }}>
{props.children}
</Typography>
);
}
class Create extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 0,
title: '',
subtitle: '',
description: '',
startDatetime: DateTime.local().plus({ days: 1 }).startOf('day'),
endDatetime: DateTime.local().plus({ days: 8 }).startOf('day'),
formulaId: '',
plotterId: '',
prizes: [],
rules: [],
};
}
handleTabChange = (event, value) => {
this.setState({ value });
}
handleEventChange = (newType, newVal) => {
this.setState({ [newType]: newVal });
}
remapPrizes = (prizes) => {
const remappedPrizes = [];
prizes.forEach((prize) => {
remappedPrizes.push({
condition: {
from: parseInt(prize.from, 10),
to: parseInt(prize.to, 10),
additional: prize.additional,
},
pool: {
amount: parseInt(prize.amount, 10),
asset: prize.asset,
},
});
});
return remappedPrizes;
}
render() {
const {
title,
subtitle,
description,
startDatetime,
endDatetime,
value,
formulaId,
plotterId,
prizes,
rules,
} = this.state;
const { classes } = this.props;
return (
<React.Fragment>
<BannerTopBar backgroundUrl='https://superalgos.org/img/photos/events.jpg' />
<Mutation mutation={hostedEventsCalls.EVENTS_CREATEEVENT}
update={(store, { data }) => {
this.props.history.push(`/events/edit/${data.events_CreateEvent.id}`);
}
}
>
{hostEvent => (
<div className={classes.root}>
<AppBar position='static' color='default'>
<Tabs
value={value}
onChange={this.handleTabChange}
scrollable
scrollButtons='off'
indicatorColor='primary'
textColor='primary'
>
<Tab
className={classes.tabTitle}
label='Basic information'
icon={<BasicIcon />}
/>
<Tab
className={classes.tabTitle}
label='Technical information'
icon={<TechnicalIcon />}
/>
<Tab
className={classes.tabTitle}
label='Teams &amp; server setup(disabled)'
icon={<TeamAndServerIcon />}
disabled
/>
<Tab
className={classes.tabTitle}
label='Presentation page(disabled)'
icon={<PresentationIcon />}
disabled
/>
</Tabs>
</AppBar>
<div className='container'>
<Paper className={classes.paperRoot}>
<Typography className={classes.typography} variant='h5' gutterBottom>
Create a new event
</Typography>
{value === 0 && <TabContainer>
<Basic
event={{
title,
subtitle,
description,
startDatetime,
endDatetime,
}}
edit={(newType, newVal) => this.handleEventChange(newType, newVal)}
create={() => hostEvent({
variables: {
event: {
title,
subtitle,
description,
startDatetime: startDatetime.valueOf() / 1000,
endDatetime: endDatetime.valueOf() / 1000,
formulaId,
plotterId,
prizes: this.remapPrizes(prizes),
rules,
},
},
})}
/>
</TabContainer>}
{value === 1 && <TabContainer>
<Technical
event={{
formulaId,
plotterId,
prizes,
rules,
}}
edit={(newType, newVal) => this.handleEventChange(newType, newVal)}
create={() => hostEvent({
variables: {
event: {
title,
subtitle,
description,
startDatetime: startDatetime.valueOf() / 1000,
endDatetime: endDatetime.valueOf() / 1000,
formulaId,
plotterId,
prizes: this.remapPrizes(prizes),
rules,
},
},
})}
/>
</TabContainer>}
{value === 2 && <TabContainer><TeamsServer /></TabContainer>}
{value === 3 && <TabContainer><PresentationPage /></TabContainer>}
</Paper>
</div>
</div>
)}
</Mutation>
</React.Fragment>
);
}
}
export default withStyles(styles)(Create);
@@ -0,0 +1,51 @@
const styles = theme => ({
root: {
flexGrow: 1,
width: '100%',
backgroundColor: theme.palette.background.paper,
padding: 0,
margin: 0,
},
tabTitle: {
width: '25%',
maxWidth: 'none',
},
clickable: {
cursor: 'pointer',
},
buttonList: {
margin: theme.spacing.unit,
float: 'right',
},
buttonGrid: {
marginTop: -20,
},
title: {
marginTop: 20,
},
paperRoot: {
flexGrow: 1,
padding: 10,
marginTop: 25,
marginBottom: 25,
},
inputField: {
width: '80%',
marginLeft: '10%',
marginTop: 25,
},
typography: {
width: '80%',
marginLeft: '10%',
marginTop: 40,
},
selectEmpty: {
marginTop: theme.spacing.unit * 2,
},
bottomButton: {
padding: 15,
margin: 20,
},
});
export default styles;
@@ -0,0 +1,111 @@
import React from 'react';
import {
TextField,
Button,
FormGroup,
Typography,
Grid,
} from '@material-ui/core';
import {
ChevronLeft,
ChevronRight,
} from '@material-ui/icons';
import { DateTimePicker } from 'material-ui-pickers';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class Basic extends React.Component {
render() {
const {
classes, event, edit, saveChanges,
} = this.props;
return (
<React.Fragment>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
These are the basic information you need to input in order to edit an event.
There might be some heavy changes in the near future as the application is still at a very early stage.
</Typography>
<TextField
label='Public id'
value={`${event.id}(your public ID is generated automatically and unmutable)`}
className={classes.inputField}
disabled
/>
<TextField
label='Title'
value={event.title}
className={classes.inputField}
onChange={newVal => edit('title', newVal.target.value)}
/>
<TextField
label='Subtitle'
value={event.subtitle}
className={classes.inputField}
onChange={newVal => edit('subtitle', newVal.target.value)}
/>
<TextField
multiline
label='Description'
value={event.description}
className={classes.inputField}
onChange={newVal => edit('description', newVal.target.value)}
/>
<FormGroup row className={classes.inputField}>
<Grid container justify='space-around' >
<Grid item>
<DateTimePicker
autoOk
disablePast
format="DD' at 'HH:mm"
ampm={false}
showTabs={false}
leftArrowIcon={<ChevronLeft />}
rightArrowIcon={<ChevronRight />}
value={event.startDatetime}
helperText='Competition start date'
onChange={newVal => edit('startDatetime', newVal)}
/>
</Grid>
<Grid item>
<DateTimePicker
autoOk
disablePast
format="DD' at 'HH:mm"
ampm={false}
showTabs={false}
leftArrowIcon={<ChevronLeft />}
rightArrowIcon={<ChevronRight />}
value={event.endDatetime}
helperText='Competition ending date'
onChange={newVal => edit('endDatetime', newVal)}
/>
</Grid>
</Grid>
</FormGroup>
<Grid container justify='center' >
<Grid item>
<Button
className={classes.bottomButton}
variant='contained'
color='secondary'
onClick={() => edit('value', 1)}
>
Go to technical tab
</Button>
<Button className={classes.bottomButton} onClick={() => saveChanges()} variant='contained' color='secondary'>
Or Edit event
</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
}
export default withStyles(styles)(Basic);
@@ -0,0 +1,27 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class PresentationPage extends React.Component {
render() {
const { classes } = this.props;
return (
<React.Fragment>
<Typography
className={classes.title}
variant='h4'
align='center'
color='textPrimary'
gutterBottom
>
PresentationPage
</Typography>
</React.Fragment>
);
}
}
export default withStyles(styles)(PresentationPage);
@@ -0,0 +1,27 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class TeamsServer extends React.Component {
render() {
const { classes } = this.props;
return (
<React.Fragment>
<Typography
className={classes.title}
variant='h4'
align='center'
color='textPrimary'
gutterBottom
>
TeamsServer
</Typography>
</React.Fragment>
);
}
}
export default withStyles(styles)(TeamsServer);
@@ -0,0 +1,78 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
import { Mutation } from 'react-apollo';
import { getOptionsCalls } from '../../../../../../GraphQL/Calls/index';
class New extends React.Component {
constructor() {
super();
this.state = { name: '' };
}
render() {
const { name } = this.state;
const { closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='createFormula-dialog-title'
>
<DialogTitle id='createFormula-dialog-title'>
Create a new formula
</DialogTitle>
<DialogContent>
<DialogContentText>
At least for now, all the formulas are publically available, creating it here will let you select it in the select element.
</DialogContentText>
<Mutation mutation={getOptionsCalls.EVENTS_CREATEFORMULA}
update={(store, { data }) => {
const { events_Formulas: formulas } = store.readQuery({
query: getOptionsCalls.EVENTS_FORMULAS,
});
store.writeQuery({
query: getOptionsCalls.EVENTS_FORMULAS,
data: { events_Formulas: formulas.concat([data.events_CreateFormula]) },
});
closeDialogs();
}
}
>
{createFormula => (
<form
onSubmit={(e) => {
e.preventDefault();
createFormula({
variables: {
formula: { name },
},
});
}}
>
<TextField
label='Name'
value={name}
onChange={e => this.setState({ name: e.target.value })}
fullWidth
/>
<Button type='submit' variant='contained' color='secondary'>Create a new formula</Button>
</form>
)}
</Mutation>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,5 @@
import New from './New';
export {
New,
};
@@ -0,0 +1,108 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
import { Mutation } from 'react-apollo';
import { getOptionsCalls } from '../../../../../../GraphQL/Calls/index';
class New extends React.Component {
constructor() {
super();
this.state = {
name: '',
host: '',
repo: '',
moduleName: '',
};
}
render() {
const {
name, host, repo, moduleName,
} = this.state;
const { closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='createPlotter-dialog-title'
>
<DialogTitle id='createPlotter-dialog-title'>
Create a new plotter
</DialogTitle>
<DialogContent>
<DialogContentText>
At least for now, all the plotters are publically available, creating it here will let you select it in the select element.
</DialogContentText>
<Mutation mutation={getOptionsCalls.EVENTS_CREATEPLOTTER}
update={(store, { data }) => {
const { events_Plotters: plotters } = store.readQuery({
query: getOptionsCalls.EVENTS_PLOTTERS,
});
store.writeQuery({
query: getOptionsCalls.EVENTS_PLOTTERS,
data: { events_Plotters: plotters.concat([data.events_CreatePlotter]) },
});
closeDialogs();
}
}
>
{createPlotter => (
<form
onSubmit={(e) => {
e.preventDefault();
createPlotter({
variables: {
plotter: {
name,
host,
repo,
moduleName,
},
},
});
}}
>
<TextField
label='Name'
value={name}
onChange={e => this.setState({ name: e.target.value })}
fullWidth
/>
<TextField
label='Host'
value={host}
onChange={e => this.setState({ host: e.target.value })}
fullWidth
/>
<TextField
label='Repository'
value={repo}
onChange={e => this.setState({ repo: e.target.value })}
fullWidth
/>
<TextField
label='Module Name'
value={moduleName}
onChange={e => this.setState({ moduleName: e.target.value })}
fullWidth
/>
<Button type='submit' variant='contained' color='secondary'>Create a new plotter</Button>
</form>
)}
</Mutation>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,5 @@
import New from './New';
export {
New,
};
@@ -0,0 +1,72 @@
import React from 'react';
import {
Paper,
Grid,
Typography,
} from '@material-ui/core';
import {
SortableContainer,
SortableElement,
SortableHandle,
} from 'react-sortable-hoc';
const DragHandle = SortableHandle(() => <div className='dragHandle' />);
const SortableItem = SortableElement(({ value, deletePrize, index }) => (
<div className='sortableListItem'>
<Grid container spacing={16}>
<Grid item>
<DragHandle />
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={16}>
<Typography gutterBottom variant="subtitle1">
{value.from}{value.to}{value.additional}{value.amount}{value.asset}
</Typography>
<Typography color="textSecondary">
</Typography>
</Grid>
<Grid item>
<Typography style={{ cursor: 'pointer' }} onClick={() => deletePrize(index)} >Remove</Typography>
</Grid>
</Grid>
</Grid>
</div>
));
const SortableList = SortableContainer(({ items, deletePrize }) => (
<div className='sortableList'>
{items.map((value, index) => (
<SortableItem key={`prize-${index}`} index={index} value={value} deletePrize={deleteId => deletePrize(deleteId)} />
))}
</div>
));
class List extends React.Component {
onSortEnd = ({ oldIndex, newIndex }) => {
const newPrizes = this.props.prizes.slice(0);
newPrizes.splice(newIndex, 0, newPrizes.splice(oldIndex, 1)[0]);
this.props.edit(newPrizes);
}
deletePrize = (deletedIndex) => {
const newPrizes = this.props.prizes.slice(0);
newPrizes.splice(deletedIndex, 1);
this.props.edit(newPrizes);
}
render() {
return (
<Paper>
<SortableList
items={this.props.prizes}
onSortEnd={this.onSortEnd}
useDragHandle={true}
deletePrize={deleteId => this.deletePrize(deleteId)}
/>
</Paper>
);
}
}
export default List;
@@ -0,0 +1,106 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
class New extends React.Component {
constructor() {
super();
this.state = {
additional: '',
amount: 0,
asset: '',
};
}
render() {
const {
from, to, additional, amount, asset,
} = this.state;
const { addPrize, closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='addPrize-dialog-title'
>
<DialogContent>
<DialogContentText>
Prizes are define textually only. In case of infringement, contact us.
</DialogContentText>
<form
onSubmit={(e) => {
e.preventDefault();
addPrize({
from,
to,
additional,
amount,
asset,
});
}}
>
<DialogTitle>
Conditions :
</DialogTitle>
<DialogContentText>
Examples :
If you want to make a price for the best bot only, you set both from and to rank to 1.
If you want the rest of the top 10 to get a price, you add a new price with from rank set to 2 and to rank set to 10.
Caution :
- Leaving &quot;from rank&quot; empty considers it to 0.
- Leaving &quot;to rank&quot; empty considers it as infinite
- Prizes are define in an additive manner, meaning that if a team qualifies for two prices, it gets both.
- Additional allows you to write addionnal textual condition, like &quot;positive ROI only&quot; for example.
</DialogContentText>
<TextField
label='From rank'
value={from}
onChange={e => this.setState({ from: e.target.value })}
type="number"
/>
<TextField
label='To rank'
value={to}
onChange={e => this.setState({ to: e.target.value })}
type="number"
/>
<TextField
label='Additional'
value={additional}
onChange={e => this.setState({ additional: e.target.value })}
fullWidth
/>
<DialogContentText>
Pool :
</DialogContentText>
<DialogContentText>
Here you define the pool, the amount is a number whereas asset is a text. For example 1BTC, 200$, or whatever.
</DialogContentText>
<TextField
label='Amount'
value={amount}
onChange={e => this.setState({ amount: e.target.value })}
type="number"
/>
<TextField
label='Asset'
value={asset}
onChange={e => this.setState({ asset: e.target.value })}
/>
<Button type='submit' variant='contained' color='secondary'>Create a new prize</Button>
</form>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,7 @@
import List from './List';
import New from './New';
export {
List,
New,
};
@@ -0,0 +1,73 @@
import React from 'react';
import {
Paper,
Grid,
Typography,
} from '@material-ui/core';
import {
SortableContainer,
SortableElement,
SortableHandle,
} from 'react-sortable-hoc';
const DragHandle = SortableHandle(() => <div className='dragHandle' />);
const SortableItem = SortableElement(({ value, deleteRule, index }) => (
<div className='sortableListItem'>
<Grid container spacing={16}>
<Grid item>
<DragHandle />
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={16}>
<Typography gutterBottom variant="subtitle1">
{value.title}
</Typography>
<Typography color="textSecondary">
{value.description}
</Typography>
</Grid>
<Grid item>
<Typography style={{ cursor: 'pointer' }} onClick={() => deleteRule(index)} >Remove</Typography>
</Grid>
</Grid>
</Grid>
</div>
));
const SortableList = SortableContainer(({ items, deleteRule }) => (
<div className='sortableList'>
{items.map((value, index) => (
<SortableItem key={`rule-${index}`} index={index} value={value} deleteRule={deleteId => deleteRule(deleteId)} />
))}
</div>
));
class List extends React.Component {
onSortEnd = ({ oldIndex, newIndex }) => {
const newRules = this.props.rules.slice(0);
newRules.splice(newIndex, 0, newRules.splice(oldIndex, 1)[0]);
this.props.edit(newRules);
}
deleteRule = (deletedIndex) => {
const newRules = this.props.rules.slice(0);
newRules.splice(deletedIndex, 1);
this.props.edit(newRules);
}
render() {
return (
<Paper>
<SortableList
items={this.props.rules}
onSortEnd={this.onSortEnd}
useDragHandle={true}
deleteRule={deleteId => this.deleteRule(deleteId)}
/>
</Paper>
);
}
}
export default List;
@@ -0,0 +1,68 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
class New extends React.Component {
constructor() {
super();
this.state = {
title: '',
description: '',
};
}
render() {
const {
title, description,
} = this.state;
const { addRule, closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='addRule-dialog-title'
>
<DialogTitle id='addRule-dialog-title'>
Create a new rule
</DialogTitle>
<DialogContent>
<DialogContentText>
Rules are define textually only. In case of infringement, contact us.
</DialogContentText>
<form
onSubmit={(e) => {
e.preventDefault();
addRule(
title,
description,
);
}}
>
<TextField
label='Title'
value={title}
onChange={e => this.setState({ title: e.target.value })}
fullWidth
/>
<TextField
label='Description'
value={description}
onChange={e => this.setState({ description: e.target.value })}
fullWidth
/>
<Button type='submit' variant='contained' color='secondary'>Create a new rule</Button>
</form>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,7 @@
import List from './List';
import New from './New';
export {
List,
New,
};
@@ -0,0 +1,196 @@
import React from 'react';
import { Query } from 'react-apollo';
import {
Typography,
FormControl,
InputLabel,
Input,
Select,
FormHelperText,
MenuItem,
Grid,
Button,
} from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../../styles';
import { getOptionsCalls } from '../../../../../GraphQL/Calls/index';
import { List as RulesList, New as NewRule } from './Rules';
import { List as PrizesList, New as NewPrize } from './Prizes';
import { New as NewPlotter } from './Plotter';
import { New as NewFormula } from './Formula';
class Technical extends React.Component {
constructor(props) {
super(props);
this.state = {
isNewFormulaOpen: false,
isNewPlotterOpen: false,
isNewRuleOpen: false,
isNewPrizeOpen: false,
};
}
addRule = (title, description) => {
this.props.edit('rules', [...this.props.event.rules, {
title,
description,
}]);
this.closeDialogs();
}
addPrize = (prize) => {
this.props.edit('prizes', [...this.props.event.prizes, prize]);
this.closeDialogs();
}
closeDialogs = () => {
this.setState({
isNewFormulaOpen: false,
isNewPlotterOpen: false,
isNewRuleOpen: false,
isNewPrizeOpen: false,
});
}
render() {
const {
classes, event, edit, saveChanges,
} = this.props;
const {
isNewPlotterOpen, isNewFormulaOpen, isNewRuleOpen, isNewPrizeOpen,
} = this.state;
return (
<React.Fragment>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
Select the formula and the plotter you want to use, you can also create your own with the corresponding button.
</Typography>
<FormControl className={classes.inputField}>
<InputLabel shrink htmlFor='select'>
Select the formula
</InputLabel>
<Query query={getOptionsCalls.EVENTS_FORMULAS} >
{({ loading, error, data }) => {
if (loading) {
return (
<Select
value='loading'
input={<Input />}
displayEmpty
className={classes.selectEmpty}
disabled
>
<MenuItem key='1' value='loading'>Loading possibilities...</MenuItem>
</Select>
);
}
if (error) return `Error! ${error.message}`;
const selects = data.events_Formulas.map((formula, index) => (
<MenuItem key={index} value={formula.id}>{formula.name}</MenuItem>
));
return (
<React.Fragment>
<Select
value={event.formulaId}
input={<Input />}
displayEmpty
className={classes.selectEmpty}
onChange={newVal => edit('formulaId', newVal.target.value)}
>
{selects}
</Select>
{ isNewFormulaOpen ? <NewFormula closeDialogs={() => this.closeDialogs()} /> : ''}
</React.Fragment>
);
}}
</Query>
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewFormulaOpen: true }); }}>
To create a new formula, click here
</FormHelperText>
</FormControl>
<FormControl className={classes.inputField}>
<InputLabel shrink htmlFor='select'>
Select the Plotter
</InputLabel>
<Query query={getOptionsCalls.EVENTS_PLOTTERS} >
{({ loading, error, data }) => {
if (loading) {
return (
<Select
value='loading'
input={<Input />}
displayEmpty
className={classes.selectEmpty}
disabled
>
<MenuItem key='1' value='loading'>Loading possibilities...</MenuItem>
</Select>
);
}
if (error) return `Error! ${error.message}`;
const selects = data.events_Plotters.map((plotter, index) => (
<MenuItem key={index} value={plotter.id}>{plotter.name}</MenuItem>
));
return (
<React.Fragment>
<Select
value={event.plotterId}
input={<Input />}
displayEmpty
className={classes.selectEmpty}
onChange={newVal => edit('plotterId', newVal.target.value)}
>
{selects}
</Select>
{ isNewPlotterOpen ? <NewPlotter closeDialogs={() => this.closeDialogs()} /> : ''}
</React.Fragment>
);
}}
</Query>
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewPlotterOpen: true }); }} >
To create a new plotter, click here
</FormHelperText>
</FormControl>
<FormControl className={classes.inputField}>
<Typography variant='h5'>
Define the rules of your event.
</Typography>
<RulesList rules={event.rules} edit={newVal => edit('rules', newVal)} />
{ isNewRuleOpen
? <NewRule closeDialogs={() => this.closeDialogs()} addRule={(title, description) => this.addRule(title, description)} />
: ''}
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewRuleOpen: true }); }} >
To add a new rule, click here
</FormHelperText>
</FormControl>
<FormControl className={classes.inputField}>
<Typography variant='h5'>
Define the prizes of your event.
</Typography>
<PrizesList prizes={event.prizes} edit={newVal => edit('prizes', newVal)} />
{ isNewPrizeOpen
? <NewPrize closeDialogs={() => this.closeDialogs()} addPrize={prize => this.addPrize(prize)} />
: ''}
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewPrizeOpen: true }); }} >
To add a new prize, click here
</FormHelperText>
</FormControl>
<Grid container justify='center' >
<Grid item>
<Button className={classes.bottomButton} onClick={ () => saveChanges() } variant='contained' color='secondary'>
Edit the event
</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
}
export default withStyles(styles)(Technical);
@@ -0,0 +1,11 @@
import Basic from './Basic';
import PresentationPage from './PresentationPage';
import TeamsServer from './TeamsServer';
import Technical from './Technical';
export {
Basic,
PresentationPage,
TeamsServer,
Technical,
};
@@ -0,0 +1,33 @@
import React from 'react';
import { Query } from 'react-apollo';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles';
import Queried from './queried';
import BannerTopBar from '../../BannerTopBar';
import { showEventCalls } from '../../../GraphQL/Calls/index';
class Edit extends React.Component {
render() {
return (
<React.Fragment>
<BannerTopBar backgroundUrl='https://superalgos.org/img/photos/events.jpg' />
<Query
query={showEventCalls.EVENTS_EVENT}
variables={{ eventId: this.props.match.params.slug }}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (<Queried event={data.events_Event} />);
}}
</Query>
</React.Fragment>
);
}
}
export default withStyles(styles)(Edit);
@@ -0,0 +1,228 @@
import React from 'react';
import { Mutation } from 'react-apollo';
import {
Paper,
Typography,
AppBar,
Tabs,
Tab,
} from '@material-ui/core';
import {
Face as BasicIcon,
Alarm as TechnicalIcon,
Group as TeamAndServerIcon,
PresentToAll as PresentationIcon,
} from '@material-ui/icons';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles';
import {
Basic,
PresentationPage,
TeamsServer,
Technical,
} from './Tabs';
import { hostedEventsCalls } from '../../../GraphQL/Calls/index';
function TabContainer(props) {
return (
<Typography component='div' style={{ padding: 8 * 3 }}>
{props.children}
</Typography>
);
}
class Queried extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 0,
id: this.props.event.id,
title: this.props.event.title,
subtitle: this.props.event.subtitle,
description: this.props.event.description,
startDatetime: this.props.event.startDatetime * 1000,
endDatetime: this.props.event.endDatetime * 1000,
formulaId: this.props.event.formula.id,
plotterId: this.props.event.plotter.id,
prizes: this.counterremapPrizes(this.props.event.prizes),
rules: this.props.event.rules,
};
}
handleTabChange = (event, value) => {
this.setState({ value });
}
handleEventChange = (newType, newVal) => {
this.setState({ [newType]: newVal });
}
counterremapPrizes = (prizes) => {
const counterremapPrizes = [];
prizes.forEach((prize) => {
counterremapPrizes.push({
from: parseInt(prize.condition.from, 10),
to: parseInt(prize.condition.to, 10),
additional: prize.condition.additional,
amount: parseInt(prize.pool.amount, 10),
asset: prize.pool.asset,
});
});
return counterremapPrizes;
}
remapPrizes = (prizes) => {
const remappedPrizes = [];
prizes.forEach((prize) => {
remappedPrizes.push({
condition: {
from: parseInt(prize.from, 10),
to: parseInt(prize.to, 10),
additional: prize.additional,
},
pool: {
amount: parseInt(prize.amount, 10),
asset: prize.asset,
},
});
});
return remappedPrizes;
}
render() {
const {
id,
title,
subtitle,
description,
startDatetime,
endDatetime,
value,
formulaId,
plotterId,
prizes,
rules,
} = this.state;
const { classes } = this.props;
return (
<React.Fragment>
<Mutation mutation={hostedEventsCalls.EVENTS_EDITEVENT}
update={(store, { data }) => {
this.props.history.push(`/events/edit/${data.events_EditEvent.id}`);
}}
>
{editHosted => (
<div className={classes.root}>
<AppBar position='static' color='default'>
<Tabs
value={value}
onChange={this.handleTabChange}
scrollable
scrollButtons='off'
indicatorColor='primary'
textColor='primary'
>
<Tab
className={classes.tabTitle}
label='Basic information'
icon={<BasicIcon />}
/>
<Tab
className={classes.tabTitle}
label='Technical information'
icon={<TechnicalIcon />}
/>
<Tab
className={classes.tabTitle}
label='Teams &amp; server setup(disabled)'
icon={<TeamAndServerIcon />}
disabled
/>
<Tab
className={classes.tabTitle}
label='Presentation page(disabled)'
icon={<PresentationIcon />}
disabled
/>
</Tabs>
</AppBar>
<div className='container'>
<Paper className={classes.paperRoot}>
<Typography className={classes.typography} variant='h5' gutterBottom>
Edit an event
</Typography>
{value === 0 && <TabContainer>
<Basic
event={{
id,
title,
subtitle,
description,
startDatetime,
endDatetime,
prizes,
rules,
}}
edit={(newType, newVal) => this.handleEventChange(newType, newVal)}
saveChanges={() => editHosted({
variables: {
eventId: id,
event: {
title,
subtitle,
description,
startDatetime: startDatetime.valueOf() / 1000,
endDatetime: endDatetime.valueOf() / 1000,
formulaId,
plotterId,
prizes: this.remapPrizes(prizes),
rules,
},
},
})}
/>
</TabContainer>}
{value === 1 && <TabContainer>
<Technical
event={{
formulaId,
plotterId,
prizes,
rules,
}}
edit={(newType, newVal) => this.handleEventChange(newType, newVal)}
saveChanges={() => editHosted({
variables: {
eventId: id,
event: {
title,
subtitle,
description,
startDatetime: startDatetime.valueOf() / 1000,
endDatetime: endDatetime.valueOf() / 1000,
formulaId,
plotterId,
prizes: this.remapPrizes(prizes),
rules,
},
},
})}
/>
</TabContainer>}
{value === 2 && <TabContainer><TeamsServer /></TabContainer>}
{value === 3 && <TabContainer><PresentationPage /></TabContainer>}
</Paper>
</div>
</div>
)}
</Mutation>
</React.Fragment>
);
}
}
export default withStyles(styles)(Queried);
@@ -0,0 +1,51 @@
const styles = theme => ({
root: {
flexGrow: 1,
width: '100%',
backgroundColor: theme.palette.background.paper,
padding: 0,
margin: 0,
},
tabTitle: {
width: '25%',
maxWidth: 'none',
},
clickable: {
cursor: 'pointer',
},
buttonList: {
margin: theme.spacing.unit,
float: 'right',
},
buttonGrid: {
marginTop: -20,
},
title: {
marginTop: 20,
},
paperRoot: {
flexGrow: 1,
padding: 10,
marginTop: 25,
marginBottom: 25,
},
inputField: {
width: '80%',
marginLeft: '10%',
marginTop: 25,
},
typography: {
width: '80%',
marginLeft: '10%',
marginTop: 40,
},
selectEmpty: {
marginTop: theme.spacing.unit * 2,
},
bottomButton: {
padding: 15,
margin: 20,
},
});
export default styles;
@@ -0,0 +1,111 @@
import React from 'react';
import {
TextField,
Button,
FormGroup,
Typography,
Grid,
} from '@material-ui/core';
import {
ChevronLeft,
ChevronRight,
} from '@material-ui/icons';
import { DateTimePicker } from 'material-ui-pickers';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class Basic extends React.Component {
render() {
const {
classes, event, edit, create,
} = this.props;
return (
<React.Fragment>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
These are the basic information you need to input in order to create an event.
There might be some heavy changes in the near future as the application is still at a very early stage.
</Typography>
<TextField
label='Public id'
value='Your public ID will be generated automatically'
className={classes.inputField}
disabled
/>
<TextField
label='Title'
value={event.title}
className={classes.inputField}
onChange={newVal => edit('title', newVal.target.value)}
/>
<TextField
label='Subtitle'
value={event.subtitle}
className={classes.inputField}
onChange={newVal => edit('subtitle', newVal.target.value)}
/>
<TextField
multiline
label='Description'
value={event.description}
className={classes.inputField}
onChange={newVal => edit('description', newVal.target.value)}
/>
<FormGroup row className={classes.inputField}>
<Grid container justify='space-around' >
<Grid item>
<DateTimePicker
autoOk
disablePast
format="DD' at 'HH:mm"
ampm={false}
showTabs={false}
leftArrowIcon={<ChevronLeft />}
rightArrowIcon={<ChevronRight />}
value={event.startDatetime}
helperText='Competition start date'
onChange={newVal => edit('startDatetime', newVal)}
/>
</Grid>
<Grid item>
<DateTimePicker
autoOk
disablePast
format="DD' at 'HH:mm"
ampm={false}
showTabs={false}
leftArrowIcon={<ChevronLeft />}
rightArrowIcon={<ChevronRight />}
value={event.endDatetime}
helperText='Competition ending date'
onChange={newVal => edit('endDatetime', newVal)}
/>
</Grid>
</Grid>
</FormGroup>
<Grid container justify='center' >
<Grid item>
<Button
className={classes.bottomButton}
variant='contained'
color='secondary'
onClick={() => edit('value', 1)}
>
Go to technical tab
</Button>
<Button className={classes.bottomButton} onClick={() => create()} variant='contained' color='secondary'>
Or Create event
</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
}
export default withStyles(styles)(Basic);
@@ -0,0 +1,27 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class PresentationPage extends React.Component {
render() {
const { classes } = this.props;
return (
<React.Fragment>
<Typography
className={classes.title}
variant='h4'
align='center'
color='textPrimary'
gutterBottom
>
PresentationPage
</Typography>
</React.Fragment>
);
}
}
export default withStyles(styles)(PresentationPage);
@@ -0,0 +1,27 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class TeamsServer extends React.Component {
render() {
const { classes } = this.props;
return (
<React.Fragment>
<Typography
className={classes.title}
variant='h4'
align='center'
color='textPrimary'
gutterBottom
>
TeamsServer
</Typography>
</React.Fragment>
);
}
}
export default withStyles(styles)(TeamsServer);
@@ -0,0 +1,78 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
import { Mutation } from 'react-apollo';
import { getOptionsCalls } from '../../../../../../GraphQL/Calls/index';
class New extends React.Component {
constructor() {
super();
this.state = { name: '' };
}
render() {
const { name } = this.state;
const { closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='createFormula-dialog-title'
>
<DialogTitle id='createFormula-dialog-title'>
Create a new formula
</DialogTitle>
<DialogContent>
<DialogContentText>
At least for now, all the formulas are publically available, creating it here will let you select it in the select element.
</DialogContentText>
<Mutation mutation={getOptionsCalls.EVENTS_CREATEFORMULA}
update={(store, { data }) => {
const { events_Formulas: formulas } = store.readQuery({
query: getOptionsCalls.EVENTS_FORMULAS,
});
store.writeQuery({
query: getOptionsCalls.EVENTS_FORMULAS,
data: { events_Formulas: formulas.concat([data.events_CreateFormula]) },
});
closeDialogs();
}
}
>
{createFormula => (
<form
onSubmit={(e) => {
e.preventDefault();
createFormula({
variables: {
formula: { name },
},
});
}}
>
<TextField
label='Name'
value={name}
onChange={e => this.setState({ name: e.target.value })}
fullWidth
/>
<Button type='submit' variant='contained' color='secondary'>Create a new formula</Button>
</form>
)}
</Mutation>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,5 @@
import New from './New';
export {
New,
};
@@ -0,0 +1,108 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
import { Mutation } from 'react-apollo';
import { getOptionsCalls } from '../../../../../../GraphQL/Calls/index';
class New extends React.Component {
constructor() {
super();
this.state = {
name: '',
host: '',
repo: '',
moduleName: '',
};
}
render() {
const {
name, host, repo, moduleName,
} = this.state;
const { closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='createPlotter-dialog-title'
>
<DialogTitle id='createPlotter-dialog-title'>
Create a new plotter
</DialogTitle>
<DialogContent>
<DialogContentText>
At least for now, all the plotters are publically available, creating it here will let you select it in the select element.
</DialogContentText>
<Mutation mutation={getOptionsCalls.EVENTS_CREATEPLOTTER}
update={(store, { data }) => {
const { events_Plotters: plotters } = store.readQuery({
query: getOptionsCalls.EVENTS_PLOTTERS,
});
store.writeQuery({
query: getOptionsCalls.EVENTS_PLOTTERS,
data: { events_Plotters: plotters.concat([data.events_CreatePlotter]) },
});
closeDialogs();
}
}
>
{createPlotter => (
<form
onSubmit={(e) => {
e.preventDefault();
createPlotter({
variables: {
plotter: {
name,
host,
repo,
moduleName,
},
},
});
}}
>
<TextField
label='Name'
value={name}
onChange={e => this.setState({ name: e.target.value })}
fullWidth
/>
<TextField
label='Host'
value={host}
onChange={e => this.setState({ host: e.target.value })}
fullWidth
/>
<TextField
label='Repository'
value={repo}
onChange={e => this.setState({ repo: e.target.value })}
fullWidth
/>
<TextField
label='Module Name'
value={moduleName}
onChange={e => this.setState({ moduleName: e.target.value })}
fullWidth
/>
<Button type='submit' variant='contained' color='secondary'>Create a new plotter</Button>
</form>
)}
</Mutation>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,5 @@
import New from './New';
export {
New,
};
@@ -0,0 +1,72 @@
import React from 'react';
import {
Paper,
Grid,
Typography,
} from '@material-ui/core';
import {
SortableContainer,
SortableElement,
SortableHandle,
} from 'react-sortable-hoc';
const DragHandle = SortableHandle(() => <div className='dragHandle' />);
const SortableItem = SortableElement(({ value, deletePrize, index }) => (
<div className='sortableListItem'>
<Grid container spacing={16}>
<Grid item>
<DragHandle />
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={16}>
<Typography gutterBottom variant="subtitle1">
{value.from}{value.to}{value.additional}{value.amount}{value.asset}
</Typography>
<Typography color="textSecondary">
</Typography>
</Grid>
<Grid item>
<Typography style={{ cursor: 'pointer' }} onClick={() => deletePrize(index)} >Remove</Typography>
</Grid>
</Grid>
</Grid>
</div>
));
const SortableList = SortableContainer(({ items, deletePrize }) => (
<div className='sortableList'>
{items.map((value, index) => (
<SortableItem key={`prize-${index}`} index={index} value={value} deletePrize={deleteId => deletePrize(deleteId)} />
))}
</div>
));
class List extends React.Component {
onSortEnd = ({ oldIndex, newIndex }) => {
const newPrizes = this.props.prizes.slice(0);
newPrizes.splice(newIndex, 0, newPrizes.splice(oldIndex, 1)[0]);
this.props.edit(newPrizes);
}
deletePrize = (deletedIndex) => {
const newPrizes = this.props.prizes.slice(0);
newPrizes.splice(deletedIndex, 1);
this.props.edit(newPrizes);
}
render() {
return (
<Paper>
<SortableList
items={this.props.prizes}
onSortEnd={this.onSortEnd}
useDragHandle={true}
deletePrize={deleteId => this.deletePrize(deleteId)}
/>
</Paper>
);
}
}
export default List;
@@ -0,0 +1,106 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
class New extends React.Component {
constructor() {
super();
this.state = {
additional: '',
amount: 0,
asset: '',
};
}
render() {
const {
from, to, additional, amount, asset,
} = this.state;
const { addPrize, closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='addPrize-dialog-title'
>
<DialogContent>
<DialogContentText>
Prizes are define textually only. In case of infringement, contact us.
</DialogContentText>
<form
onSubmit={(e) => {
e.preventDefault();
addPrize({
from,
to,
additional,
amount,
asset,
});
}}
>
<DialogTitle>
Conditions :
</DialogTitle>
<DialogContentText>
Examples :
If you want to make a price for the best bot only, you set both from and to rank to 1.
If you want the rest of the top 10 to get a price, you add a new price with from rank set to 2 and to rank set to 10.
Caution :
- Leaving &quot;from rank&quot; empty considers it to 0.
- Leaving &quot;to rank&quot; empty considers it as infinite
- Prizes are define in an additive manner, meaning that if a team qualifies for two prices, it gets both.
- Additional allows you to write addionnal textual condition, like &quot;positive ROI only&quot; for example.
</DialogContentText>
<TextField
label='From rank'
value={from}
onChange={e => this.setState({ from: e.target.value })}
type="number"
/>
<TextField
label='To rank'
value={to}
onChange={e => this.setState({ to: e.target.value })}
type="number"
/>
<TextField
label='Additional'
value={additional}
onChange={e => this.setState({ additional: e.target.value })}
fullWidth
/>
<DialogContentText>
Pool :
</DialogContentText>
<DialogContentText>
Here you define the pool, the amount is a number whereas asset is a text. For example 1BTC, 200$, or whatever.
</DialogContentText>
<TextField
label='Amount'
value={amount}
onChange={e => this.setState({ amount: e.target.value })}
type="number"
/>
<TextField
label='Asset'
value={asset}
onChange={e => this.setState({ asset: e.target.value })}
/>
<Button type='submit' variant='contained' color='secondary'>Create a new prize</Button>
</form>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,7 @@
import List from './List';
import New from './New';
export {
List,
New,
};
@@ -0,0 +1,73 @@
import React from 'react';
import {
Paper,
Grid,
Typography,
} from '@material-ui/core';
import {
SortableContainer,
SortableElement,
SortableHandle,
} from 'react-sortable-hoc';
const DragHandle = SortableHandle(() => <div className='dragHandle' />);
const SortableItem = SortableElement(({ value, deleteRule, index }) => (
<div className='sortableListItem'>
<Grid container spacing={16}>
<Grid item>
<DragHandle />
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={16}>
<Typography gutterBottom variant="subtitle1">
{value.title}
</Typography>
<Typography color="textSecondary">
{value.description}
</Typography>
</Grid>
<Grid item>
<Typography style={{ cursor: 'pointer' }} onClick={() => deleteRule(index)} >Remove</Typography>
</Grid>
</Grid>
</Grid>
</div>
));
const SortableList = SortableContainer(({ items, deleteRule }) => (
<div className='sortableList'>
{items.map((value, index) => (
<SortableItem key={`rule-${index}`} index={index} value={value} deleteRule={deleteId => deleteRule(deleteId)} />
))}
</div>
));
class List extends React.Component {
onSortEnd = ({ oldIndex, newIndex }) => {
const newRules = this.props.rules.slice(0);
newRules.splice(newIndex, 0, newRules.splice(oldIndex, 1)[0]);
this.props.edit(newRules);
}
deleteRule = (deletedIndex) => {
const newRules = this.props.rules.slice(0);
newRules.splice(deletedIndex, 1);
this.props.edit(newRules);
}
render() {
return (
<Paper>
<SortableList
items={this.props.rules}
onSortEnd={this.onSortEnd}
useDragHandle={true}
deleteRule={deleteId => this.deleteRule(deleteId)}
/>
</Paper>
);
}
}
export default List;
@@ -0,0 +1,68 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
class New extends React.Component {
constructor() {
super();
this.state = {
title: '',
description: '',
};
}
render() {
const {
title, description,
} = this.state;
const { addRule, closeDialogs } = this.props;
return (
<Dialog
open={true}
onClose={() => closeDialogs()}
aria-labelledby='addRule-dialog-title'
>
<DialogTitle id='addRule-dialog-title'>
Create a new rule
</DialogTitle>
<DialogContent>
<DialogContentText>
Rules are define textually only. In case of infringement, contact us.
</DialogContentText>
<form
onSubmit={(e) => {
e.preventDefault();
addRule(
title,
description,
);
}}
>
<TextField
label='Title'
value={title}
onChange={e => this.setState({ title: e.target.value })}
fullWidth
/>
<TextField
label='Description'
value={description}
onChange={e => this.setState({ description: e.target.value })}
fullWidth
/>
<Button type='submit' variant='contained' color='secondary'>Create a new rule</Button>
</form>
<Button onClick={() => closeDialogs()} variant='contained' color='primary'>Close</Button>
</DialogContent>
</Dialog>
);
}
}
export default New;
@@ -0,0 +1,7 @@
import List from './List';
import New from './New';
export {
List,
New,
};
@@ -0,0 +1,196 @@
import React from 'react';
import { Query } from 'react-apollo';
import {
Typography,
FormControl,
InputLabel,
Input,
Select,
FormHelperText,
MenuItem,
Grid,
Button,
} from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../../styles';
import { getOptionsCalls } from '../../../../../GraphQL/Calls/index';
import { List as RulesList, New as NewRule } from './Rules';
import { List as PrizesList, New as NewPrize } from './Prizes';
import { New as NewPlotter } from './Plotter';
import { New as NewFormula } from './Formula';
class Technical extends React.Component {
constructor(props) {
super(props);
this.state = {
isNewFormulaOpen: false,
isNewPlotterOpen: false,
isNewRuleOpen: false,
isNewPrizeOpen: false,
};
}
addRule = (title, description) => {
this.props.edit('rules', [...this.props.event.rules, {
title,
description,
}]);
this.closeDialogs();
}
addPrize = (prize) => {
this.props.edit('prizes', [...this.props.event.prizes, prize]);
this.closeDialogs();
}
closeDialogs = () => {
this.setState({
isNewFormulaOpen: false,
isNewPlotterOpen: false,
isNewRuleOpen: false,
isNewPrizeOpen: false,
});
}
render() {
const {
classes, event, edit, create,
} = this.props;
const {
isNewPlotterOpen, isNewFormulaOpen, isNewRuleOpen, isNewPrizeOpen,
} = this.state;
return (
<React.Fragment>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
Select the formula and the plotter you want to use, you can also create your own with the corresponding button.
</Typography>
<FormControl className={classes.inputField}>
<InputLabel shrink htmlFor='select'>
Select the formula
</InputLabel>
<Query query={getOptionsCalls.EVENTS_FORMULAS} >
{({ loading, error, data }) => {
if (loading) {
return (
<Select
value='loading'
input={<Input />}
displayEmpty
className={classes.selectEmpty}
disabled
>
<MenuItem key='1' value='loading'>Loading possibilities...</MenuItem>
</Select>
);
}
if (error) return `Error! ${error.message}`;
const selects = data.events_Formulas.map((formula, index) => (
<MenuItem key={index} value={formula.id}>{formula.name}</MenuItem>
));
return (
<React.Fragment>
<Select
value={event.formulaId}
input={<Input />}
displayEmpty
className={classes.selectEmpty}
onChange={newVal => edit('formulaId', newVal.target.value)}
>
{selects}
</Select>
{ isNewFormulaOpen ? <NewFormula closeDialogs={() => this.closeDialogs()} /> : ''}
</React.Fragment>
);
}}
</Query>
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewFormulaOpen: true }); }}>
To create a new formula, click here
</FormHelperText>
</FormControl>
<FormControl className={classes.inputField}>
<InputLabel shrink htmlFor='select'>
Select the Plotter
</InputLabel>
<Query query={getOptionsCalls.EVENTS_PLOTTERS} >
{({ loading, error, data }) => {
if (loading) {
return (
<Select
value='loading'
input={<Input />}
displayEmpty
className={classes.selectEmpty}
disabled
>
<MenuItem key='1' value='loading'>Loading possibilities...</MenuItem>
</Select>
);
}
if (error) return `Error! ${error.message}`;
const selects = data.events_Plotters.map((plotter, index) => (
<MenuItem key={index} value={plotter.id}>{plotter.name}</MenuItem>
));
return (
<React.Fragment>
<Select
value={event.plotterId}
input={<Input />}
displayEmpty
className={classes.selectEmpty}
onChange={newVal => edit('plotterId', newVal.target.value)}
>
{selects}
</Select>
{ isNewPlotterOpen ? <NewPlotter closeDialogs={() => this.closeDialogs()} /> : ''}
</React.Fragment>
);
}}
</Query>
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewPlotterOpen: true }); }} >
To create a new plotter, click here
</FormHelperText>
</FormControl>
<FormControl className={classes.inputField}>
<Typography variant='h5'>
Define the rules of your event.
</Typography>
<RulesList rules={event.rules} edit={newVal => edit('rules', newVal)} />
{ isNewRuleOpen
? <NewRule closeDialogs={() => this.closeDialogs()} addRule={(title, description) => this.addRule(title, description)} />
: ''}
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewRuleOpen: true }); }} >
To add a new rule, click here
</FormHelperText>
</FormControl>
<FormControl className={classes.inputField}>
<Typography variant='h5'>
Define the prizes of your event.
</Typography>
<PrizesList prizes={event.prizes} edit={newVal => edit('prizes', newVal)} />
{ isNewPrizeOpen
? <NewPrize closeDialogs={() => this.closeDialogs()} addPrize={prize => this.addPrize(prize)} />
: ''}
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewPrizeOpen: true }); }} >
To add a new prize, click here
</FormHelperText>
</FormControl>
<Grid container justify='center' >
<Grid item>
<Button className={classes.bottomButton} onClick={() => create()} variant='contained' color='secondary'>
Create the event
</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
}
export default withStyles(styles)(Technical);
@@ -0,0 +1,11 @@
import Basic from './Basic';
import PresentationPage from './PresentationPage';
import TeamsServer from './TeamsServer';
import Technical from './Technical';
export {
Basic,
PresentationPage,
TeamsServer,
Technical,
};
@@ -0,0 +1,79 @@
import React from 'react';
import { Query } from 'react-apollo';
import {
Paper,
Typography,
} from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles';
import { toLocalTime } from '../../../utils';
import BannerTopBar from '../../BannerTopBar';
import { showEventCalls } from '../../../GraphQL/Calls/index';
class Show extends React.Component {
render() {
const { classes } = this.props;
return (
<React.Fragment>
<BannerTopBar backgroundUrl='https://superalgos.org/img/photos/events.jpg' />
<div className='container'>
<Paper className={classes.paperRoot}>
<Typography className={classes.typography} variant='h4' gutterBottom>
Event Details :
</Typography>
<Query
query={showEventCalls.EVENTS_EVENT}
variables={{ eventId: this.props.match.params.slug }}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (
<React.Fragment>
<Typography className={classes.typography} variant='h5' gutterBottom>
Title :
</Typography>
<Typography className={classes.typography} variant='h6' gutterBottom>
{data.events_Event.title}
</Typography>
<Typography className={classes.typography} variant='h5' gutterBottom>
Subtitle :
</Typography>
<Typography className={classes.typography} variant='h6' gutterBottom>
{data.events_Event.subtitle}
</Typography>
<Typography className={classes.typography} variant='h5' gutterBottom>
Dates :
</Typography>
<Typography className={classes.typography} variant='h6' gutterBottom>
From {toLocalTime(data.events_Event.startDatetime)} to {toLocalTime(data.events_Event.endDatetime)}
</Typography>
<Typography className={classes.typography} variant='h5' gutterBottom>
Formula :
</Typography>
<Typography className={classes.typography} variant='h6' gutterBottom>
{data.events_Event.formula.name}
</Typography>
<Typography className={classes.typography} variant='h5' gutterBottom>
Plotter :
</Typography>
<Typography className={classes.typography} variant='h6' gutterBottom>
{data.events_Event.plotter.name}
</Typography>
</React.Fragment>
);
}}
</Query>
</Paper>
</div>
</React.Fragment>
);
}
}
export default withStyles(styles)(Show);
@@ -0,0 +1,51 @@
const styles = theme => ({
root: {
flexGrow: 1,
width: '100%',
backgroundColor: theme.palette.background.paper,
padding: 0,
margin: 0,
},
tabTitle: {
width: '25%',
maxWidth: 'none',
},
clickable: {
cursor: 'pointer',
},
buttonList: {
margin: theme.spacing.unit,
float: 'right',
},
buttonGrid: {
marginTop: -20,
},
title: {
marginTop: 20,
},
paperRoot: {
flexGrow: 1,
padding: 10,
marginTop: 25,
marginBottom: 25,
},
inputField: {
width: '80%',
marginLeft: '10%',
marginTop: 25,
},
typography: {
width: '80%',
marginLeft: '10%',
marginTop: 40,
},
selectEmpty: {
marginTop: theme.spacing.unit * 2,
},
bottomButton: {
padding: 15,
margin: 20,
},
});
export default styles;
@@ -0,0 +1,104 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Mutation } from 'react-apollo';
import {
Grid, Paper,
Typography,
Button,
} from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles';
import { hostedEventsCalls } from '../../GraphQL/Calls/index';
import { toLocalTime } from '../../utils';
class Event extends React.Component {
render() {
const { classes, showOnly, event } = this.props;
const {
id,
title,
subtitle,
startDatetime,
endDatetime,
host,
formula,
description,
} = event;
return (
<Paper className={classes.card}>
<Grid container spacing={16}>
<Grid item xs>
<Typography gutterBottom variant='h5'> {title} </Typography>
<Typography gutterBottom variant='h6'> {subtitle} </Typography>
<Typography gutterBottom>From : {toLocalTime(startDatetime)} </Typography>
<Typography gutterBottom>To : {toLocalTime(endDatetime)} </Typography>
</Grid>
<Grid item xs>
<Typography gutterBottom variant='h6'> Description : </Typography>
<Typography gutterBottom> {description} </Typography>
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction='column' spacing={16}>
<Grid item xs>
<Typography gutterBottom>
Hosted by: {host.alias} ({host.lastName} {host.firstName})
</Typography>
<Typography gutterBottom>Formula: {formula.name} </Typography>
</Grid>
<Grid item className={classes.buttonGrid}>
{ !showOnly
? <React.Fragment>
<Mutation mutation={hostedEventsCalls.EVENTS_PUBLISHEVENT}
update={() => {
window.location.reload();
}}
>
{publishEvent => (
<Button
className={classes.buttonList}
variant='outlined'
color='secondary'
size='small'
onClick={() => publishEvent({ variables: { eventId: id, state: 'PUBLISHED' } })}
>
Publish
</Button>
)}
</Mutation>
<Button
className={classes.buttonList}
variant='outlined'
color='primary'
size='small'
component={Link}
to={`/events/edit/${id}`}
>
Edit
</Button>
</React.Fragment>
: ''
}
<Button
className={classes.buttonList}
variant='outlined'
color='primary'
size='small'
component={Link}
to={`/events/show/${id}`}
>
Show
</Button>
</Grid>
</Grid>
</Grid>
</Grid>
</Paper>
);
}
}
export default withStyles(styles)(Event);
@@ -0,0 +1,82 @@
import React from 'react';
import { Query } from 'react-apollo';
import { Typography } from '@material-ui/core';
import { DateTime } from 'luxon';
import BannerTopBar from '../BannerTopBar';
import { hostedEventsCalls } from '../../GraphQL/Calls/index';
import Event from './Event';
const HostedEvent = () => (
<React.Fragment>
<BannerTopBar
size='medium'
title='Your hosted events'
text='You are one of the pillars of this community, thank you'
backgroundUrl='https://superalgos.org/img/photos/events.jpg'
/>
<Query
query={hostedEventsCalls.EVENTS_EVENTSBYHOST}
variables={{ hostId: 'self', state: 'UNPUBLISHED' }}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
const list = data.events_Events.map((event, index) => (
<Event showOnly={false} key={index} event={event} />
));
return (
<div className='container'>
<Typography variant='h3'> Unpublished : </Typography>
{ list }
</div>
);
}}
</Query>
<Query
query={hostedEventsCalls.EVENTS_EVENTSBYHOST}
variables={{ hostId: 'self', minEndDate: Math.floor(DateTime.local().valueOf() / 1000) }}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
const list = data.events_Events.map((event, index) => (
<Event showOnly={true} key={index} event={event} />
));
return (
<div className='container'>
<Typography variant='h3'> Published : </Typography>
{ list }
</div>
);
}}
</Query>
<Query
query={hostedEventsCalls.EVENTS_EVENTSBYHOST}
variables={{ hostId: 'self', maxEndDate: Math.floor(DateTime.local().valueOf() / 1000) }}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
const list = data.events_Events.map((event, index) => (
<Event showOnly={true} key={index} event={event} />
));
return (
<div className='container'>
<Typography variant='h3'> Old : </Typography>
{ list }
</div>
);
}}
</Query>
</React.Fragment>
);
export default HostedEvent;
@@ -0,0 +1,17 @@
const styles = theme => ({
card: {
flexGrow: 1,
padding: 20,
marginTop: 20,
marginBottom: 20,
},
buttonList: {
margin: theme.spacing.unit,
float: 'right',
},
buttonGrid: {
marginTop: -20,
},
});
export default styles;
@@ -0,0 +1,164 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Mutation } from 'react-apollo';
import {
Grid, Paper,
Typography,
Button,
Select,
MenuItem,
} from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles';
import { hostedEventsCalls } from '../../GraphQL/Calls/index';
import { toLocalTime } from '../../utils';
class Event extends React.Component {
constructor() {
super();
this.state = {
keyId: '',
participantId: '',
botId: '',
};
}
render() {
const { keyId, participantId, botId } = this.state;
const {
classes,
event,
availableKey = [],
enrollable = false,
} = this.props;
const {
id,
title,
subtitle,
startDatetime,
endDatetime,
host,
formula,
description,
participatingAs,
canParticipateAs,
} = event;
const fbs = [];
canParticipateAs.forEach((team) => {
team.fb.forEach((finb) => {
fbs.push({
value: `${team.id}|${finb.id}`,
text: `${team.name} > ${finb.name}`,
});
});
});
return (
<Paper className={classes.card}>
<Grid container spacing={16}>
<Grid item xs>
<Typography gutterBottom variant='h5'> {title} </Typography>
<Typography gutterBottom variant='h6'> {subtitle} </Typography>
<Typography gutterBottom>From : {toLocalTime(startDatetime)} </Typography>
<Typography gutterBottom>To : {toLocalTime(endDatetime)} </Typography>
</Grid>
<Grid item xs>
<Typography gutterBottom variant='h6'> Description : </Typography>
<Typography gutterBottom> {description} </Typography>
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction='column' spacing={16}>
<Grid item xs>
<Typography gutterBottom>
Hosted by: {host.alias} ({host.lastName} {host.firstName})
</Typography>
<Typography gutterBottom>Formula: {formula.name} </Typography>
<Typography gutterBottom>You are participating as : { participatingAs.map(team => `${team.name}, `) } </Typography>
</Grid>
<Grid item className={classes.buttonGrid}>
{ enrollable && fbs.length
? <Mutation mutation={hostedEventsCalls.REGISTER_EVENT}
update={() => {
window.location.reload();
}}
>
{enrollToEvent => (
<React.Fragment>
<Select
value={`${participantId}|${botId}`}
onChange={(val) => {
this.setState({
participantId: val.target.value.split('|')[0],
botId: val.target.value.split('|')[1],
});
}}
name='bot'
displayEmpty
className={classes.selectEmpty}
>
<MenuItem value='|' disabled>
Enroll as :
</MenuItem>
{ fbs.map(finb => <MenuItem
key={finb.value}
value={finb.value}>{finb.text}</MenuItem>) }
</Select>
<Select
value={keyId}
onChange={(val) => { this.setState({ keyId: val.target.value }); }}
name='key'
displayEmpty
className={classes.selectEmpty}
>
<MenuItem value='' disabled>
Select key
</MenuItem>
{ availableKey.map(akey => <MenuItem
key={akey.id}
value={akey.id}>{akey.key}</MenuItem>) }
</Select>
<Button
className={classes.buttonList}
variant='outlined'
color='secondary'
size='small'
onClick={() => enrollToEvent({
variables: {
eventId: id,
keyId,
participantId,
botId,
},
})}
>
Enroll
</Button>
</React.Fragment>
)}
</Mutation>
: ''
}
<Button
className={classes.buttonList}
variant='outlined'
color='primary'
size='small'
component={Link}
to={`/events/show/${id}`}
>
Show
</Button>
</Grid>
</Grid>
</Grid>
</Grid>
</Paper>
);
}
}
export default withStyles(styles)(Event);
@@ -0,0 +1,34 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
import Event from '../Event';
class Future extends React.Component {
render() {
const { classes } = this.props;
const { Events, AKey } = this.props;
const events = Events.map((event, index) => (
<Event key={index} event={event} availableKey={AKey} enrollable={true} />
));
return (
<div className='container'>
<Typography
className={classes.title}
variant='h4'
align='center'
color='textPrimary'
gutterBottom
>
Future events
</Typography>
{events}
</div>
);
}
}
export default withStyles(styles)(Future);
@@ -0,0 +1,26 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class History extends React.Component {
render() {
const { classes } = this.props;
return (
<div className='container'>
<Typography
className={classes.title}
variant='h4'
align='center'
color='textPrimary'
gutterBottom
>
Your old events (comming soon)
</Typography>
</div>
);
}
}
export default withStyles(styles)(History);
@@ -0,0 +1,33 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
import Event from '../Event';
class Ongoing extends React.Component {
render() {
const { Events, classes } = this.props;
const events = Events.map((event, index) => (
<Event key={index} event={event} />
));
return (
<div className='container'>
<Typography
className={classes.title}
variant='h4'
align='center'
color='textPrimary'
gutterBottom
>
Ongoing events:
</Typography>
{events}
</div>
);
}
}
export default withStyles(styles)(Ongoing);
@@ -0,0 +1,34 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
import Event from '../Event';
class Past extends React.Component {
render() {
const { classes } = this.props;
const { PastEvents } = this.props;
const pastEvents = PastEvents.map((event, index) => (
<Event key={index} event={event} />
));
return (
<div className='container'>
<Typography
className={classes.title}
variant='display1'
align='center'
color='textPrimary'
gutterBottom
>
A list of passed events
</Typography>
{pastEvents}
</div>
);
}
}
export default withStyles(styles)(Past);
@@ -0,0 +1,11 @@
import Future from './Future';
import History from './History';
import Ongoing from './Ongoing';
import Past from './Past';
export {
Future,
History,
Ongoing,
Past,
};
@@ -0,0 +1,157 @@
import React from 'react';
import { Query } from 'react-apollo';
import { DateTime } from 'luxon';
import {
Typography,
AppBar,
Tabs,
Tab,
} from '@material-ui/core';
import {
GetApp as OngoingIcon,
AlarmAdd as FutureIcon,
History as HistoryIcon,
} from '@material-ui/icons';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles';
import BannerTopBar from '../BannerTopBar';
import { hostedEventsCalls } from '../../GraphQL/Calls/index';
import {
Future,
History,
Ongoing,
Past,
} from './Tabs';
function TabContainer(props) {
return (
<Typography component='div' style={{ padding: 8 * 3 }}>
{props.children}
</Typography>
);
}
class Search extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 0,
};
}
handleChange = (event, value) => {
this.setState({ value });
}
render() {
const { classes } = this.props;
const { value } = this.state;
const time = { now: Math.floor(DateTime.local().valueOf() / 1000) };
return (
<React.Fragment>
<BannerTopBar
size='medium'
title='Events'
text='All the events are going to be listed here'
backgroundUrl='https://superalgos.org/img/photos/events.jpg'
/>
<div className={classes.root}>
<AppBar position='static' color='default'>
<Tabs
value={value}
onChange={this.handleChange}
scrollable
scrollButtons='off'
indicatorColor='primary'
textColor='primary'
>
<Tab
className={classes.tabTitle}
label='Ongoing'
icon={<OngoingIcon />}
/>
<Tab
className={classes.tabTitle}
label='Future'
icon={<FutureIcon />}
/>
<Tab
className={classes.tabTitle}
label='Your history'
icon={<HistoryIcon />}
/>
<Tab
className={classes.tabTitle}
label='Past'
icon={<HistoryIcon />}
/>
</Tabs>
</AppBar>
<Query
query={hostedEventsCalls.EVENTS_EVENTSBYHOST}
variables={{ maxStartDate: time.now, minEndDate: time.now }}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (
<React.Fragment>
{value === 0 && <TabContainer><Ongoing Events={data.events_Events} /></TabContainer>}
</React.Fragment>
);
}}
</Query>
<Query
query={hostedEventsCalls.EVENTS_EVENT_AND_AKEY}
variables={{ minStartDate: time.now }}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (
<React.Fragment>
{value === 1 && <TabContainer><Future Events={data.events_Events} AKey={data.keyVault_AvailableKeys} /></TabContainer>}
</React.Fragment>
);
}}
</Query>
<Query
query={hostedEventsCalls.EVENTS_EVENTSBYHOST}
variables={{ maxEndDate: time.now }}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (
<React.Fragment>
{value === 2 && <TabContainer><History Events={data.events_Events} /></TabContainer>}
</React.Fragment>
);
}}
</Query>
<Query
query={hostedEventsCalls.EVENTS_EVENTSBYHOST}
variables={{ maxEndDate: time.now }}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (
<React.Fragment>
{value === 3 && <TabContainer><Past PastEvents={data.events_Events} /></TabContainer>}
</React.Fragment>
);
}}
</Query>
</div>
</React.Fragment>
);
}
}
export default withStyles(styles)(Search);
@@ -0,0 +1,31 @@
const styles = theme => ({
root: {
flexGrow: 1,
width: '100%',
backgroundColor: theme.palette.background.paper,
padding: 0,
margin: 0,
},
tabTitle: {
width: '25%',
maxWidth: 'none',
},
card: {
flexGrow: 1,
padding: 20,
marginTop: 20,
marginBottom: 20,
},
buttonList: {
margin: theme.spacing.unit,
float: 'right',
},
buttonGrid: {
marginTop: -20,
},
title: {
marginTop: 20,
},
});
export default styles;
@@ -0,0 +1,45 @@
import gql from 'graphql-tag';
import { formulaInfo, plotterInfo } from '../Fragments';
const EVENTS_FORMULAS = gql`
query Events_Formulas{
events_Formulas {
...FormulaInfo
}
}
${formulaInfo}
`;
const EVENTS_PLOTTERS = gql`
query Events_Plotters{
events_Plotters {
...PlotterInfo
}
}
${plotterInfo}
`;
const EVENTS_CREATEFORMULA = gql`
mutation Events_CreateFormula($formula: events_FormulaInput!) {
events_CreateFormula(formula: $formula) {
...FormulaInfo
}
}
${formulaInfo}
`;
const EVENTS_CREATEPLOTTER = gql`
mutation Events_CreatePlotter($plotter: events_PlotterInput!) {
events_CreatePlotter(plotter: $plotter) {
...PlotterInfo
}
}
${plotterInfo}
`;
export default {
EVENTS_PLOTTERS,
EVENTS_FORMULAS,
EVENTS_CREATEFORMULA,
EVENTS_CREATEPLOTTER,
};
@@ -0,0 +1,100 @@
import gql from 'graphql-tag';
import { eventFullInfo } from '../Fragments';
const EVENTS_CREATEEVENT = gql`
mutation Events_CreateEvent($event: events_EventInput!) {
events_CreateEvent(event: $event) {
...EventFullInfo
}
}
${eventFullInfo}
`;
const EVENTS_EDITEVENT = gql`
mutation Events_EditEvent($eventId: ID!, $event: events_EventInput!) {
events_EditEvent(eventId: $eventId, event: $event) {
...EventFullInfo
}
}
${eventFullInfo}
`;
const EVENTS_EVENTSBYHOST = gql`
query Events_Events(
$hostId: String,
$state: events_EventStateEnum,
$minStartDate: Int,
$maxStartDate: Int,
$minEndDate: Int,
$maxEndDate: Int
){
events_Events(
hostId: $hostId,
state: $state,
minStartDate: $minStartDate,
maxStartDate: $maxStartDate,
minEndDate: $minEndDate,
maxEndDate: $maxEndDate
) {
...EventFullInfo
}
}
${eventFullInfo}
`;
const EVENTS_EVENT_AND_AKEY = gql`
query Events_Events(
$hostId: String,
$state: events_EventStateEnum,
$minStartDate: Int,
$maxStartDate: Int,
$minEndDate: Int,
$maxEndDate: Int
){
events_Events(
hostId: $hostId,
state: $state,
minStartDate: $minStartDate,
maxStartDate: $maxStartDate,
minEndDate: $minEndDate,
maxEndDate: $maxEndDate
) {
...EventFullInfo
}
keyVault_AvailableKeys{
id
key
}
}
${eventFullInfo}
`;
const EVENTS_PUBLISHEVENT = gql`
mutation Events_ChangeEventState($eventId: ID!, $state: events_EventStateEnum) {
events_ChangeEventState(eventId: $eventId, state: $state) {
...EventFullInfo
}
}
${eventFullInfo}
`;
const REGISTER_EVENT = gql`
mutation Events_RegisterToEvent($eventId: ID!, $keyId: String!, $participantId: String!, $botId: String!) {
events_RegisterToEvent(
eventId: $eventId
participant: { keyId: $keyId, participantId: $participantId, botId: $botId }
) {
...EventFullInfo
}
}
${eventFullInfo}
`;
export default {
EVENTS_CREATEEVENT,
EVENTS_EDITEVENT,
EVENTS_EVENTSBYHOST,
EVENTS_EVENT_AND_AKEY,
EVENTS_PUBLISHEVENT,
REGISTER_EVENT,
};
@@ -0,0 +1,11 @@
import hostedEventsCalls from './hostedEvents';
import listEventsCalls from './listEvents';
import showEventCalls from './showEvent';
import getOptionsCalls from './getOptions';
export {
hostedEventsCalls,
listEventsCalls,
showEventCalls,
getOptionsCalls,
};
@@ -0,0 +1,15 @@
import gql from 'graphql-tag';
import { eventFullInfo } from '../Fragments';
const EVENTS_EVENTS = gql`
query Events_Events($minStartDate: Int, $maxStartDate: Int, $minEndDate: Int, $maxEndDate: Int){
events_Events(minStartDate: $minStartDate, maxStartDate: $maxStartDate, minEndDate: $minEndDate, maxEndDate: $maxEndDate) {
...EventFullInfo
}
}
${eventFullInfo}
`;
export default {
EVENTS_EVENTS,
};
@@ -0,0 +1,15 @@
import gql from 'graphql-tag';
import { eventFullInfo } from '../Fragments';
const EVENTS_EVENT = gql`
query Events_Event($eventId: ID!) {
events_Event(eventId: $eventId) {
...EventFullInfo
}
}
${eventFullInfo}
`;
export default {
EVENTS_EVENT,
};
@@ -0,0 +1,138 @@
import gql from 'graphql-tag';
export const eventMinimalInfo = gql`
fragment EventMinimalInfo on events_Event {
id
state
title
startDatetime
endDatetime
host {
alias
firstName
lastName
}
description
formula{
name
}
plotter{
name
}
}
`;
export const eventFullInfo = gql`
fragment EventFullInfo on events_Event {
id
title
subtitle
hostId
host {
id
email
firstName
middleName
lastName
}
description
startDatetime
endDatetime
state
rules {
title
description
}
prizes {
condition {
from
to
additional
}
pool {
amount
asset
}
}
participants {
participantId
participant {
id
name
}
state
operationId
clone{
botId
}
}
participatingAs{
id
name
}
canParticipateAs{
id
name
fb{
id
name
}
}
invitations {
inviteeId
invitee {
id
name
}
acceptedDate
refusedDate
by {
date
inviterId
inviter {
id
email
firstName
middleName
lastName
}
}
}
presentation {
banner
profile
page
}
formula {
id
ownerId
owner {
id
email
firstName
middleName
lastName
}
isTemplate
name
}
plotter {
id
ownerId
owner {
id
email
firstName
middleName
lastName
}
isTemplate
name
host
repo
moduleName
}
}
`;
@@ -0,0 +1,15 @@
import {
eventMinimalInfo,
eventFullInfo,
} from './event';
import {
formulaInfo,
plotterInfo,
} from './options';
export {
eventMinimalInfo,
eventFullInfo,
formulaInfo,
plotterInfo,
};
@@ -0,0 +1,22 @@
import gql from 'graphql-tag';
export const plotterInfo = gql`
fragment PlotterInfo on events_Plotter {
id
ownerId
isTemplate
name
host
repo
moduleName
}
`;
export const formulaInfo = gql`
fragment FormulaInfo on events_Formula {
id
ownerId
isTemplate
name
}
`;
@@ -0,0 +1,29 @@
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import { MuiPickersUtilsProvider } from 'material-ui-pickers';
import LuxonUtils from 'material-ui-pickers/utils/luxon-utils';
import Search from './Components/Search';
import HostedEvents from './Components/HostedEvents';
import EditEvent from './Components/Event/Edit';
import ShowEvent from './Components/Event/Show';
import CreateEvent from './Components/Event/Create';
import './styles.scss';
const App = () => (
<MuiPickersUtilsProvider utils={LuxonUtils}>
<div className='eventsModule'>
<Switch>
<Route exact path='/events/' component={Search} />
<Route path='/events/create' component={CreateEvent} />
<Route path='/events/edit/:slug' component={EditEvent} />
<Route path='/events/show/:slug' component={ShowEvent} />
<Route path='/events/host' component={HostedEvents} />
</Switch>
</div>
</MuiPickersUtilsProvider>
);
export default App;
@@ -0,0 +1,22 @@
.eventsModule{
.sortableListItem{
padding-top: 15px;
margin-right: 15px;
padding-bottom: 15px;
margin-left: 15px;
border-bottom: 1px solid rgba(142, 144, 146, 0.3);
}
}
.dragHandle{
position: relative;
top: 1px;
display: block;
width: 18px;
height: 11px;
opacity: .25;
margin-right: 20px;
cursor: row-resize;
background: -webkit-linear-gradient(top,#000,#000 20%,#fff 0,#fff 40%,#000 0,#000 60%,#fff 0,#fff 80%,#000 0,#000);
background: linear-gradient(180deg,#000,#000 20%,#fff 0,#fff 40%,#000 0,#000 60%,#fff 0,#fff 80%,#000 0,#000);
}
@@ -0,0 +1,12 @@
export const toLocalTime = (epoch) => {
const localDate = new Date(0);
localDate.setUTCSeconds(epoch);
const options = { year: 'numeric', month: 'long', day: '2-digit' };
return (
`${localDate.toLocaleDateString(options)
} at ${
localDate.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' })}`
);
};
export const temporaryFunction = input => input;
@@ -0,0 +1,9 @@
const getItem = async name => window.localStorage.getItem(name);
const setItem = async (name, value) => window.localStorage.setItem(name, value);
const removeItem = async name => window.localStorage.removeItem(name);
export {
getItem,
setItem,
removeItem,
};