diff --git a/src/Components/Event/Create/Tabs/Basic.js b/src/Components/Event/Create/Tabs/Basic.js index a65394acd..6854ea420 100644 --- a/src/Components/Event/Create/Tabs/Basic.js +++ b/src/Components/Event/Create/Tabs/Basic.js @@ -56,12 +56,6 @@ class Basic extends React.Component { onChange={newVal => edit('description', newVal.target.value)} /> - - The dates are purely indicative, as it is important for you to make sure everything is - ready before manually triggering the beginning and end of the event. - If you are confident use the scheduler to start it for you(incoming). - - diff --git a/src/Components/Event/Edit/Tabs/Basic.js b/src/Components/Event/Edit/Tabs/Basic.js index 910099532..8210a3720 100644 --- a/src/Components/Event/Edit/Tabs/Basic.js +++ b/src/Components/Event/Edit/Tabs/Basic.js @@ -25,7 +25,7 @@ class Basic extends React.Component { return ( - These are the basic information you need to input in order to create an event. + 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. @@ -56,12 +56,6 @@ class Basic extends React.Component { onChange={newVal => edit('description', newVal.target.value)} /> - - The dates are purely indicative, as it is important for you to make sure everything is - ready before manually triggering the beginning and end of the event. - If you are confident use the scheduler to start it for you(incoming). - - @@ -105,7 +99,7 @@ class Basic extends React.Component { Go to technical tab diff --git a/src/Components/Event/Edit/Tabs/Technical/index.js b/src/Components/Event/Edit/Tabs/Technical/index.js index 5cccd7490..212aa6d50 100644 --- a/src/Components/Event/Edit/Tabs/Technical/index.js +++ b/src/Components/Event/Edit/Tabs/Technical/index.js @@ -184,7 +184,7 @@ class Technical extends React.Component { diff --git a/src/Components/Event/Edit/queried.js b/src/Components/Event/Edit/queried.js index b7ae18c2e..3ba72b60a 100644 --- a/src/Components/Event/Edit/queried.js +++ b/src/Components/Event/Edit/queried.js @@ -153,7 +153,7 @@ class Queried extends React.Component {
- Create a new event + Edit an event {value === 0 && + + 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. + + + + + edit('title', newVal.target.value)} + /> + edit('subtitle', newVal.target.value)} + /> + edit('description', newVal.target.value)} + /> + + + + + } + rightArrowIcon={} + value={event.startDatetime} + helperText='Competition start date' + onChange={newVal => edit('startDatetime', newVal)} + /> + + + } + rightArrowIcon={} + value={event.endDatetime} + helperText='Competition ending date' + onChange={newVal => edit('endDatetime', newVal)} + /> + + + + + + + + + + + ); + } +} + +export default withStyles(styles)(Basic); diff --git a/src/Components/Event/Show/Tabs/PresentationPage.js b/src/Components/Event/Show/Tabs/PresentationPage.js new file mode 100644 index 000000000..1c674ddcc --- /dev/null +++ b/src/Components/Event/Show/Tabs/PresentationPage.js @@ -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 ( + + + PresentationPage + + + ); + } +} + +export default withStyles(styles)(PresentationPage); diff --git a/src/Components/Event/Show/Tabs/TeamsServer.js b/src/Components/Event/Show/Tabs/TeamsServer.js new file mode 100644 index 000000000..874c72d6f --- /dev/null +++ b/src/Components/Event/Show/Tabs/TeamsServer.js @@ -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 ( + + + TeamsServer + + + ); + } +} + +export default withStyles(styles)(TeamsServer); diff --git a/src/Components/Event/Show/Tabs/Technical/Formula/New.js b/src/Components/Event/Show/Tabs/Technical/Formula/New.js new file mode 100644 index 000000000..605782b2d --- /dev/null +++ b/src/Components/Event/Show/Tabs/Technical/Formula/New.js @@ -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 ( + closeDialogs()} + aria-labelledby='createFormula-dialog-title' + > + + Create a new formula + + + + At least for now, all the formulas are publically available, creating it here will let you select it in the select element. + + + { + 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 => ( +
{ + e.preventDefault(); + createFormula({ + variables: { + formula: { name }, + }, + }); + }} + > + this.setState({ name: e.target.value })} + fullWidth + /> + + + )} +
+ +
+
+ ); + } +} + +export default New; diff --git a/src/Components/Event/Show/Tabs/Technical/Formula/index.js b/src/Components/Event/Show/Tabs/Technical/Formula/index.js new file mode 100644 index 000000000..6f7047dad --- /dev/null +++ b/src/Components/Event/Show/Tabs/Technical/Formula/index.js @@ -0,0 +1,5 @@ +import New from './New'; + +export { + New, +}; diff --git a/src/Components/Event/Show/Tabs/Technical/Plotter/New.js b/src/Components/Event/Show/Tabs/Technical/Plotter/New.js new file mode 100644 index 000000000..5dc2b3b06 --- /dev/null +++ b/src/Components/Event/Show/Tabs/Technical/Plotter/New.js @@ -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 ( + closeDialogs()} + aria-labelledby='createPlotter-dialog-title' + > + + Create a new plotter + + + + At least for now, all the plotters are publically available, creating it here will let you select it in the select element. + + + { + 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 => ( +
{ + e.preventDefault(); + createPlotter({ + variables: { + plotter: { + name, + host, + repo, + moduleName, + }, + }, + }); + }} + > + this.setState({ name: e.target.value })} + fullWidth + /> + this.setState({ host: e.target.value })} + fullWidth + /> + this.setState({ repo: e.target.value })} + fullWidth + /> + this.setState({ moduleName: e.target.value })} + fullWidth + /> + + + )} +
+ +
+
+ ); + } +} + +export default New; diff --git a/src/Components/Event/Show/Tabs/Technical/Plotter/index.js b/src/Components/Event/Show/Tabs/Technical/Plotter/index.js new file mode 100644 index 000000000..6f7047dad --- /dev/null +++ b/src/Components/Event/Show/Tabs/Technical/Plotter/index.js @@ -0,0 +1,5 @@ +import New from './New'; + +export { + New, +}; diff --git a/src/Components/Event/Show/Tabs/Technical/Prizes/List.js b/src/Components/Event/Show/Tabs/Technical/Prizes/List.js new file mode 100644 index 000000000..cc807f2c2 --- /dev/null +++ b/src/Components/Event/Show/Tabs/Technical/Prizes/List.js @@ -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(() =>
); + +const SortableItem = SortableElement(({ value, deletePrize, index }) => ( +
+ + + + + + + + {value.from}{value.to}{value.additional}{value.amount}{value.asset} + + + + + + deletePrize(index)} >Remove + + + +
+)); + +const SortableList = SortableContainer(({ items, deletePrize }) => ( +
+ {items.map((value, index) => ( + deletePrize(deleteId)} /> + ))} +
+)); + +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 ( + + this.deletePrize(deleteId)} + /> + + ); + } +} + +export default List; diff --git a/src/Components/Event/Show/Tabs/Technical/Prizes/New.js b/src/Components/Event/Show/Tabs/Technical/Prizes/New.js new file mode 100644 index 000000000..53d702b4e --- /dev/null +++ b/src/Components/Event/Show/Tabs/Technical/Prizes/New.js @@ -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 ( + closeDialogs()} + aria-labelledby='addPrize-dialog-title' + > + + + Prizes are define textually only. In case of infringement, contact us. + +
{ + e.preventDefault(); + addPrize({ + from, + to, + additional, + amount, + asset, + }); + }} + > + + Conditions : + + + 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. + + + this.setState({ from: e.target.value })} + type="number" + /> + this.setState({ to: e.target.value })} + type="number" + /> + this.setState({ additional: e.target.value })} + fullWidth + /> + + Pool : + + + Here you define the pool, the amount is a number whereas asset is a text. For example 1BTC, 200$, or whatever. + + this.setState({ amount: e.target.value })} + type="number" + /> + this.setState({ asset: e.target.value })} + /> + + + +
+
+ ); + } +} + +export default New; diff --git a/src/Components/Event/Show/Tabs/Technical/Prizes/index.js b/src/Components/Event/Show/Tabs/Technical/Prizes/index.js new file mode 100644 index 000000000..307bbe029 --- /dev/null +++ b/src/Components/Event/Show/Tabs/Technical/Prizes/index.js @@ -0,0 +1,7 @@ +import List from './List'; +import New from './New'; + +export { + List, + New, +}; diff --git a/src/Components/Event/Show/Tabs/Technical/Rules/List.js b/src/Components/Event/Show/Tabs/Technical/Rules/List.js new file mode 100644 index 000000000..e2966ae7d --- /dev/null +++ b/src/Components/Event/Show/Tabs/Technical/Rules/List.js @@ -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(() =>
); + +const SortableItem = SortableElement(({ value, deleteRule, index }) => ( +
+ + + + + + + + {value.title} + + + {value.description} + + + + deleteRule(index)} >Remove + + + +
+)); + +const SortableList = SortableContainer(({ items, deleteRule }) => ( +
+ {items.map((value, index) => ( + deleteRule(deleteId)} /> + ))} +
+)); + +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 ( + + this.deleteRule(deleteId)} + /> + + ); + } +} + +export default List; diff --git a/src/Components/Event/Show/Tabs/Technical/Rules/New.js b/src/Components/Event/Show/Tabs/Technical/Rules/New.js new file mode 100644 index 000000000..e133c1508 --- /dev/null +++ b/src/Components/Event/Show/Tabs/Technical/Rules/New.js @@ -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 ( + closeDialogs()} + aria-labelledby='addRule-dialog-title' + > + + Create a new rule + + + + Rules are define textually only. In case of infringement, contact us. + +
{ + e.preventDefault(); + addRule( + title, + description, + ); + }} + > + this.setState({ title: e.target.value })} + fullWidth + /> + this.setState({ description: e.target.value })} + fullWidth + /> + + + +
+
+ ); + } +} + +export default New; diff --git a/src/Components/Event/Show/Tabs/Technical/Rules/index.js b/src/Components/Event/Show/Tabs/Technical/Rules/index.js new file mode 100644 index 000000000..307bbe029 --- /dev/null +++ b/src/Components/Event/Show/Tabs/Technical/Rules/index.js @@ -0,0 +1,7 @@ +import List from './List'; +import New from './New'; + +export { + List, + New, +}; diff --git a/src/Components/Event/Show/Tabs/Technical/index.js b/src/Components/Event/Show/Tabs/Technical/index.js new file mode 100644 index 000000000..1840c37fb --- /dev/null +++ b/src/Components/Event/Show/Tabs/Technical/index.js @@ -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 ( + + + Select the formula and the plotter you want to use, you can also create your own with the corresponding button. + + + + Select the formula + + + {({ loading, error, data }) => { + if (loading) { + return ( + + ); + } + if (error) return `Error! ${error.message}`; + const selects = data.events_Formulas.map((formula, index) => ( + {formula.name} + )); + return ( + + + { isNewFormulaOpen ? this.closeDialogs()} /> : ''} + + ); + }} + + { this.setState({ isNewFormulaOpen: true }); }}> + To create a new formula, click here + + + + + Select the Plotter + + + {({ loading, error, data }) => { + if (loading) { + return ( + + ); + } + if (error) return `Error! ${error.message}`; + const selects = data.events_Plotters.map((plotter, index) => ( + {plotter.name} + )); + return ( + + + { isNewPlotterOpen ? this.closeDialogs()} /> : ''} + + ); + }} + + { this.setState({ isNewPlotterOpen: true }); }} > + To create a new plotter, click here + + + + + + Define the rules of your event. + + edit('rules', newVal)} /> + { isNewRuleOpen + ? this.closeDialogs()} addRule={(title, description) => this.addRule(title, description)} /> + : ''} + { this.setState({ isNewRuleOpen: true }); }} > + To add a new rule, click here + + + + + + Define the prizes of your event. + + edit('prizes', newVal)} /> + { isNewPrizeOpen + ? this.closeDialogs()} addPrize={prize => this.addPrize(prize)} /> + : ''} + { this.setState({ isNewPrizeOpen: true }); }} > + To add a new prize, click here + + + + + + + + + + ); + } +} + +export default withStyles(styles)(Technical); diff --git a/src/Components/Event/Show/Tabs/index.js b/src/Components/Event/Show/Tabs/index.js new file mode 100644 index 000000000..feecaaf55 --- /dev/null +++ b/src/Components/Event/Show/Tabs/index.js @@ -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, +}; diff --git a/src/Components/Event/Show/index.js b/src/Components/Event/Show/index.js index 4c83b98bd..b37a17302 100644 --- a/src/Components/Event/Show/index.js +++ b/src/Components/Event/Show/index.js @@ -1,39 +1,76 @@ import React from 'react'; import { Query } from 'react-apollo'; -import Typography from '@material-ui/core/Typography'; +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 ( - - Enroll in an competition {this.props.match.params.slug} - - - {({ loading, error, data }) => { - if (loading) return 'Loading...'; - if (error) return `Error! ${error.message}`; - return ( -

- {data.events_Event.description} -

- ); - }} -
+ +
+ + + Event Details : + + + + {({ loading, error, data }) => { + if (loading) return 'Loading...'; + if (error) return `Error! ${error.message}`; + return ( + + + Title : + + + {data.events_Event.title} + + + Subtitle : + + + {data.events_Event.subtitle} + + + Dates : + + + From {toLocalTime(data.events_Event.startDatetime)} to {toLocalTime(data.events_Event.endDatetime)} + + + Formula : + + + {data.events_Event.formula.name} + + + Plotter : + + + {data.events_Event.plotter.name} + + + ); + }} + + +
); } diff --git a/src/Components/Event/Show/styles.js b/src/Components/Event/Show/styles.js index 12fd82051..50a3490ca 100644 --- a/src/Components/Event/Show/styles.js +++ b/src/Components/Event/Show/styles.js @@ -1,4 +1,51 @@ -const styles = () => ({ +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; diff --git a/src/index.js b/src/index.js index 2fbbce84c..b08dca31f 100644 --- a/src/index.js +++ b/src/index.js @@ -7,6 +7,7 @@ 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'; @@ -18,7 +19,7 @@ const App = () => ( - +