Events Client Module moved to old repos
This commit is contained in:
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);
|
||||
+78
@@ -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;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import New from './New';
|
||||
|
||||
export {
|
||||
New,
|
||||
};
|
||||
+108
@@ -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;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import New from './New';
|
||||
|
||||
export {
|
||||
New,
|
||||
};
|
||||
+72
@@ -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;
|
||||
+106
@@ -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 "from rank" empty considers it to 0.
|
||||
- Leaving "to rank" 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 "positive ROI only" 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;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import List from './List';
|
||||
import New from './New';
|
||||
|
||||
export {
|
||||
List,
|
||||
New,
|
||||
};
|
||||
+73
@@ -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;
|
||||
+68
@@ -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;
|
||||
+7
@@ -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 & 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);
|
||||
+78
@@ -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;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import New from './New';
|
||||
|
||||
export {
|
||||
New,
|
||||
};
|
||||
+108
@@ -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;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import New from './New';
|
||||
|
||||
export {
|
||||
New,
|
||||
};
|
||||
+72
@@ -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;
|
||||
+106
@@ -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 "from rank" empty considers it to 0.
|
||||
- Leaving "to rank" 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 "positive ROI only" 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;
|
||||
+7
@@ -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 & 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);
|
||||
+78
@@ -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;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import New from './New';
|
||||
|
||||
export {
|
||||
New,
|
||||
};
|
||||
+108
@@ -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;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import New from './New';
|
||||
|
||||
export {
|
||||
New,
|
||||
};
|
||||
+72
@@ -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;
|
||||
+106
@@ -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 "from rank" empty considers it to 0.
|
||||
- Leaving "to rank" 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 "positive ROI only" 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;
|
||||
+7
@@ -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,
|
||||
};
|
||||
Reference in new issue
Block a user